+2003-08-16 Tor Lillqvist <tml@iki.fi>
+
+ Fix #117925 (Dov Grobgeld):
+
+ * glib/gutils.c (g_find_program_in_path, g_basename,
+ g_path_get_basename, g_path_is_absolute, g_path_skip_root,
+ g_path_get_dirname, g_get_any_init): On Win32, look also for
+ slashes ('/') as pathname separators.
+
+ * glib/gfileutils.c (g_file_open_tmp): Ditto. If the template
+ contains a pathname separator, include the actual one in the error
+ message, instead of always the canonical one.
+
+ (g_build_filename): Separate implementation on Win32 that looks
+ for either slash or backslash. Document Unix/Windows differences.
+
+ * tests/testglib.c
+ * tests/strfunc-test.c: Test above functionality on Win32.
+
2003-08-15 Tor Lillqvist <tml@iki.fi>
* glib/gmain.c (g_poll): [Win32] Don't exceed handle array
+2003-08-16 Tor Lillqvist <tml@iki.fi>
+
+ Fix #117925 (Dov Grobgeld):
+
+ * glib/gutils.c (g_find_program_in_path, g_basename,
+ g_path_get_basename, g_path_is_absolute, g_path_skip_root,
+ g_path_get_dirname, g_get_any_init): On Win32, look also for
+ slashes ('/') as pathname separators.
+
+ * glib/gfileutils.c (g_file_open_tmp): Ditto. If the template
+ contains a pathname separator, include the actual one in the error
+ message, instead of always the canonical one.
+
+ (g_build_filename): Separate implementation on Win32 that looks
+ for either slash or backslash. Document Unix/Windows differences.
+
+ * tests/testglib.c
+ * tests/strfunc-test.c: Test above functionality on Win32.
+
2003-08-15 Tor Lillqvist <tml@iki.fi>
* glib/gmain.c (g_poll): [Win32] Don't exceed handle array
+2003-08-16 Tor Lillqvist <tml@iki.fi>
+
+ Fix #117925 (Dov Grobgeld):
+
+ * glib/gutils.c (g_find_program_in_path, g_basename,
+ g_path_get_basename, g_path_is_absolute, g_path_skip_root,
+ g_path_get_dirname, g_get_any_init): On Win32, look also for
+ slashes ('/') as pathname separators.
+
+ * glib/gfileutils.c (g_file_open_tmp): Ditto. If the template
+ contains a pathname separator, include the actual one in the error
+ message, instead of always the canonical one.
+
+ (g_build_filename): Separate implementation on Win32 that looks
+ for either slash or backslash. Document Unix/Windows differences.
+
+ * tests/testglib.c
+ * tests/strfunc-test.c: Test above functionality on Win32.
+
2003-08-15 Tor Lillqvist <tml@iki.fi>
* glib/gmain.c (g_poll): [Win32] Don't exceed handle array
+2003-08-16 Tor Lillqvist <tml@iki.fi>
+
+ Fix #117925 (Dov Grobgeld):
+
+ * glib/gutils.c (g_find_program_in_path, g_basename,
+ g_path_get_basename, g_path_is_absolute, g_path_skip_root,
+ g_path_get_dirname, g_get_any_init): On Win32, look also for
+ slashes ('/') as pathname separators.
+
+ * glib/gfileutils.c (g_file_open_tmp): Ditto. If the template
+ contains a pathname separator, include the actual one in the error
+ message, instead of always the canonical one.
+
+ (g_build_filename): Separate implementation on Win32 that looks
+ for either slash or backslash. Document Unix/Windows differences.
+
+ * tests/testglib.c
+ * tests/strfunc-test.c: Test above functionality on Win32.
+
2003-08-15 Tor Lillqvist <tml@iki.fi>
* glib/gmain.c (g_poll): [Win32] Don't exceed handle array
+2003-08-16 Tor Lillqvist <tml@iki.fi>
+
+ Fix #117925 (Dov Grobgeld):
+
+ * glib/gutils.c (g_find_program_in_path, g_basename,
+ g_path_get_basename, g_path_is_absolute, g_path_skip_root,
+ g_path_get_dirname, g_get_any_init): On Win32, look also for
+ slashes ('/') as pathname separators.
+
+ * glib/gfileutils.c (g_file_open_tmp): Ditto. If the template
+ contains a pathname separator, include the actual one in the error
+ message, instead of always the canonical one.
+
+ (g_build_filename): Separate implementation on Win32 that looks
+ for either slash or backslash. Document Unix/Windows differences.
+
+ * tests/testglib.c
+ * tests/strfunc-test.c: Test above functionality on Win32.
+
2003-08-15 Tor Lillqvist <tml@iki.fi>
* glib/gmain.c (g_poll): [Win32] Don't exceed handle array
+2003-08-16 Tor Lillqvist <tml@iki.fi>
+
+ Fix #117925 (Dov Grobgeld):
+
+ * glib/gutils.c (g_find_program_in_path, g_basename,
+ g_path_get_basename, g_path_is_absolute, g_path_skip_root,
+ g_path_get_dirname, g_get_any_init): On Win32, look also for
+ slashes ('/') as pathname separators.
+
+ * glib/gfileutils.c (g_file_open_tmp): Ditto. If the template
+ contains a pathname separator, include the actual one in the error
+ message, instead of always the canonical one.
+
+ (g_build_filename): Separate implementation on Win32 that looks
+ for either slash or backslash. Document Unix/Windows differences.
+
+ * tests/testglib.c
+ * tests/strfunc-test.c: Test above functionality on Win32.
+
2003-08-15 Tor Lillqvist <tml@iki.fi>
* glib/gmain.c (g_poll): [Win32] Don't exceed handle array
#include "glibintl.h"
+#ifdef G_OS_WIN32
+#define G_IS_DIR_SEPARATOR(c) (c == G_DIR_SEPARATOR || c == '/')
+#else
+#define G_IS_DIR_SEPARATOR(c) (c == G_DIR_SEPARATOR)
+#endif
+
/**
* g_file_test:
* @filename: a filename to test
const char *tmpdir;
char *sep;
char *fulltemplate;
+ const char *slash;
if (tmpl == NULL)
tmpl = ".XXXXXX";
- if (strchr (tmpl, G_DIR_SEPARATOR)
+ if ((slash = strchr (tmpl, G_DIR_SEPARATOR)) != NULL
#ifdef G_OS_WIN32
- || strchr (tmpl, '/')
+ || (strchr (tmpl, '/') != NULL && (slash = "/"))
#endif
- )
+ )
{
+ char c[2];
+ c[0] = *slash;
+ c[1] = '\0';
+
g_set_error (error,
G_FILE_ERROR,
G_FILE_ERROR_FAILED,
_("Template '%s' invalid, should not contain a '%s'"),
- tmpl, G_DIR_SEPARATOR_S);
+ tmpl, c);
return -1;
}
tmpdir = g_get_tmp_dir ();
- if (tmpdir [strlen (tmpdir) - 1] == G_DIR_SEPARATOR)
+ if (G_IS_DIR_SEPARATOR (tmpdir [strlen (tmpdir) - 1]))
sep = "";
else
sep = G_DIR_SEPARATOR_S;
* @Varargs: remaining elements in path, terminated by %NULL
*
* Creates a filename from a series of elements using the correct
- * separator for filenames. This function behaves identically
- * to <literal>g_build_path (G_DIR_SEPARATOR_S, first_element, ....)</literal>.
+ * separator for filenames.
+ *
+ * On Unix, this function behaves identically to <literal>g_build_path
+ * (G_DIR_SEPARATOR_S, first_element, ....)</literal>.
+ *
+ * On Windows, it takes into account that either the backslash
+ * (<literal>\</literal> or slash (<literal>/</literal>) can be used
+ * as separator in filenames, but otherwise behaves as on Unix. When
+ * file pathname separators need to be inserted, the one that last
+ * previously occurred in the parameters (reading from left to right)
+ * is used.
*
* No attempt is made to force the resulting filename to be an absolute
* path. If the first element is a relative path, the result will
g_build_filename (const gchar *first_element,
...)
{
+#ifndef G_OS_WIN32
gchar *str;
va_list args;
va_end (args);
return str;
+#else
+ /* Code copied from g_build_pathv(), and modifed to use two
+ * alternative single-character separators.
+ */
+ va_list args;
+ GString *result;
+ gboolean is_first = TRUE;
+ gboolean have_leading = FALSE;
+ const gchar *single_element = NULL;
+ const gchar *next_element;
+ const gchar *last_trailing = NULL;
+ gchar current_separator = '\\';
+
+ va_start (args, first_element);
+
+ result = g_string_new (NULL);
+
+ next_element = first_element;
+
+ while (TRUE)
+ {
+ const gchar *element;
+ const gchar *start;
+ const gchar *end;
+
+ if (next_element)
+ {
+ element = next_element;
+ next_element = va_arg (args, gchar *);
+ }
+ else
+ break;
+
+ /* Ignore empty elements */
+ if (!*element)
+ continue;
+
+ start = element;
+
+ if (TRUE)
+ {
+ while (start &&
+ (*start == '\\' || *start == '/'))
+ {
+ current_separator = *start;
+ start++;
+ }
+ }
+
+ end = start + strlen (start);
+
+ if (TRUE)
+ {
+ while (end >= start + 1 &&
+ (end[-1] == '\\' || end[-1] == '/'))
+ {
+ current_separator = end[-1];
+ end--;
+ }
+
+ last_trailing = end;
+ while (last_trailing >= element + 1 &&
+ (last_trailing[-1] == '\\' || last_trailing[-1] == '/'))
+ last_trailing--;
+
+ if (!have_leading)
+ {
+ /* If the leading and trailing separator strings are in the
+ * same element and overlap, the result is exactly that element
+ */
+ if (last_trailing <= start)
+ single_element = element;
+
+ g_string_append_len (result, element, start - element);
+ have_leading = TRUE;
+ }
+ else
+ single_element = NULL;
+ }
+
+ if (end == start)
+ continue;
+
+ if (!is_first)
+ g_string_append_len (result, ¤t_separator, 1);
+
+ g_string_append_len (result, start, end - start);
+ is_first = FALSE;
+ }
+
+ va_end (args);
+
+ if (single_element)
+ {
+ g_string_free (result, TRUE);
+ return g_strdup (single_element);
+ }
+ else
+ {
+ if (last_trailing)
+ g_string_append (result, last_trailing);
+
+ return g_string_free (result, FALSE);
+ }
+#endif
}
/**
#include <libintl.h>
#endif
+/* G_IS_DIR_SEPARATOR probably should be made public in GLib 2.4 */
+#ifdef G_OS_WIN32
+#define G_IS_DIR_SEPARATOR(c) (c == G_DIR_SEPARATOR || c == '/')
+#else
+#define G_IS_DIR_SEPARATOR(c) (c == G_DIR_SEPARATOR)
+#endif
+
const guint glib_major_version = GLIB_MAJOR_VERSION;
const guint glib_minor_version = GLIB_MINOR_VERSION;
const guint glib_micro_version = GLIB_MICRO_VERSION;
* don't look in PATH.
*/
if (g_path_is_absolute (program)
- || strchr (program, G_DIR_SEPARATOR) != NULL)
+ || strchr (program, G_DIR_SEPARATOR) != NULL
+#ifdef G_OS_WIN32
+ || strchr (program, '/') != NULL
+#endif
+ )
{
if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE))
return g_strdup (program);
g_return_val_if_fail (file_name != NULL, NULL);
base = strrchr (file_name, G_DIR_SEPARATOR);
+
+#ifdef G_OS_WIN32
+ {
+ gchar *q = strrchr (file_name, '/');
+ if (base == NULL || (q != NULL && q > base))
+ base = q;
+ }
+#endif
+
if (base)
return base + 1;
last_nonslash = strlen (file_name) - 1;
- while (last_nonslash >= 0 && file_name [last_nonslash] == G_DIR_SEPARATOR)
+ while (last_nonslash >= 0 && G_IS_DIR_SEPARATOR (file_name [last_nonslash]))
last_nonslash--;
if (last_nonslash == -1)
base = last_nonslash;
- while (base >=0 && file_name [base] != G_DIR_SEPARATOR)
+ while (base >=0 && !G_IS_DIR_SEPARATOR (file_name [base]))
base--;
#ifdef G_OS_WIN32
{
g_return_val_if_fail (file_name != NULL, FALSE);
- if (file_name[0] == G_DIR_SEPARATOR
-#ifdef G_OS_WIN32
- || file_name[0] == '/'
-#endif
- )
+ if (G_IS_DIR_SEPARATOR (file_name[0]))
return TRUE;
#ifdef G_OS_WIN32
/* Recognize drive letter on native Windows */
- if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && (file_name[2] == G_DIR_SEPARATOR || file_name[2] == '/'))
+ if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
return TRUE;
#endif /* G_OS_WIN32 */
g_return_val_if_fail (file_name != NULL, NULL);
#ifdef G_PLATFORM_WIN32
- /* Skip \\server\share (Win32) or //server/share (Cygwin) */
- if (file_name[0] == G_DIR_SEPARATOR &&
- file_name[1] == G_DIR_SEPARATOR &&
+ /* Skip \\server\share or //server/share */
+ if (G_IS_DIR_SEPARATOR (file_name[0]) &&
+ G_IS_DIR_SEPARATOR (file_name[1]) &&
file_name[2])
{
gchar *p;
- if ((p = strchr (file_name + 2, G_DIR_SEPARATOR)) > file_name + 2 &&
+ p = strchr (file_name + 2, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+ {
+ gchar *q = strchr (file_name + 2, '/');
+ if (p == NULL || (q != NULL && q < p))
+ p = q;
+ }
+#endif
+ if (p &&
+ p > file_name + 2 &&
p[1])
{
file_name = p + 1;
- while (file_name[0] && file_name[0] != G_DIR_SEPARATOR)
+ while (file_name[0] && !G_IS_DIR_SEPARATOR (file_name[0]))
file_name++;
/* Possibly skip a backslash after the share name */
- if (file_name[0] == G_DIR_SEPARATOR)
+ if (G_IS_DIR_SEPARATOR (file_name[0]))
file_name++;
return (gchar *)file_name;
#endif
/* Skip initial slashes */
- if (file_name[0] == G_DIR_SEPARATOR)
+ if (G_IS_DIR_SEPARATOR (file_name[0]))
{
- while (file_name[0] == G_DIR_SEPARATOR)
+ while (G_IS_DIR_SEPARATOR (file_name[0]))
file_name++;
return (gchar *)file_name;
}
#ifdef G_OS_WIN32
/* Skip X:\ */
- if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
+ if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && G_IS_DIR_SEPARATOR (file_name[2]))
return (gchar *)file_name + 3;
#endif
g_return_val_if_fail (file_name != NULL, NULL);
base = strrchr (file_name, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+ {
+ gchar *q = strrchr (file_name, '/');
+ if (base == NULL || (q != NULL && q > base))
+ base = q;
+ }
+#endif
if (!base)
return g_strdup (".");
- while (base > file_name && *base == G_DIR_SEPARATOR)
+ while (base > file_name && G_IS_DIR_SEPARATOR (*base))
base--;
len = (guint) 1 + base - file_name;
gsize k;
g_tmp_dir = g_strdup (P_tmpdir);
k = strlen (g_tmp_dir);
- if (k > 1 && g_tmp_dir[k - 1] == G_DIR_SEPARATOR)
+ if (k > 1 && G_IS_DIR_SEPARATOR (g_tmp_dir[k - 1]))
g_tmp_dir[k - 1] = '\0';
}
#endif
TEST (NULL, str_check (g_build_filename (S"x"S, S"y"S, S"z"S, NULL), S"x"S"y"S"z"S));
TEST (NULL, str_check (g_build_filename (S S"x"S S, S S"y"S S, S S"z"S S, NULL), S S"x"S"y"S"z"S S));
+#ifdef G_OS_WIN32
+
+ /* Test also using the slash as file name separator */
+#define U "/"
+ TEST (NULL, str_check (g_build_filename (NULL), ""));
+ TEST (NULL, str_check (g_build_filename (U, NULL), U));
+ TEST (NULL, str_check (g_build_filename (U"x", NULL), U"x"));
+ TEST (NULL, str_check (g_build_filename ("x"U, NULL), "x"U));
+ TEST (NULL, str_check (g_build_filename ("", U"x", NULL), U"x"));
+ TEST (NULL, str_check (g_build_filename ("", U"x", NULL), U"x"));
+ TEST (NULL, str_check (g_build_filename (U, "x", NULL), U"x"));
+ TEST (NULL, str_check (g_build_filename (U U, "x", NULL), U U"x"));
+ TEST (NULL, str_check (g_build_filename (U S, "x", NULL), U S"x"));
+ TEST (NULL, str_check (g_build_filename ("x"U, "", NULL), "x"U));
+ TEST (NULL, str_check (g_build_filename ("x"S"y", "z"U"a", NULL), "x"S"y"S"z"U"a"));
+ TEST (NULL, str_check (g_build_filename ("x", U, NULL), "x"U));
+ TEST (NULL, str_check (g_build_filename ("x", U U, NULL), "x"U U));
+ TEST (NULL, str_check (g_build_filename ("x", S U, NULL), "x"S U));
+ TEST (NULL, str_check (g_build_filename (U"x", "y", NULL), U"x"U"y"));
+ TEST (NULL, str_check (g_build_filename ("x", "y"U, NULL), "x"U"y"U));
+ TEST (NULL, str_check (g_build_filename (U"x"U, U"y"U, NULL), U"x"U"y"U));
+ TEST (NULL, str_check (g_build_filename (U"x"U U, U U"y"U, NULL), U"x"U"y"U));
+ TEST (NULL, str_check (g_build_filename ("x", U, "y", NULL), "x"U"y"));
+ TEST (NULL, str_check (g_build_filename ("x", U U, "y", NULL), "x"U"y"));
+ TEST (NULL, str_check (g_build_filename ("x", U S, "y", NULL), "x"S"y"));
+ TEST (NULL, str_check (g_build_filename ("x", S U, "y", NULL), "x"U"y"));
+ TEST (NULL, str_check (g_build_filename ("x", U "y", "z", NULL), "x"U"y"U"z"));
+ TEST (NULL, str_check (g_build_filename ("x", S "y", "z", NULL), "x"S"y"S"z"));
+ TEST (NULL, str_check (g_build_filename ("x", S "y", "z", U, "a", "b", NULL), "x"S"y"S"z"U"a"U"b"));
+ TEST (NULL, str_check (g_build_filename (U"x"U, U"y"U, U"z"U, NULL), U"x"U"y"U"z"U));
+ TEST (NULL, str_check (g_build_filename (U U"x"U U, U U"y"U U, U U"z"U U, NULL), U U"x"U"y"U"z"U U));
+#endif /* G_OS_WIN32 */
+
#undef S
{
gchar *filename;
gchar *dirname;
} dirname_checks[] = {
-#ifndef G_OS_WIN32
{ "/", "/" },
{ "////", "/" },
{ ".////", "." },
{ "a/b", "a" },
{ "a/b/", "a/b" },
{ "c///", "c" },
-#else
+#ifdef G_OS_WIN32
{ "\\", "\\" },
{ ".\\\\\\\\", "." },
{ "..\\", ".." },
{ "..\\\\\\\\", ".." },
{ "a\\b", "a" },
- { "a\\b\\", "a\\b" },
- { "c\\\\\\", "c" },
+ { "a\\b/", "a\\b" },
+ { "a/b\\", "a/b" },
+ { "c\\\\/", "c" },
+ { "//\\", "/" },
#endif
#ifdef G_WITH_CYGWIN
{ "//server/share///x", "//server/share" },
gchar *filename;
gchar *without_root;
} skip_root_checks[] = {
-#ifndef G_OS_WIN32
{ "/", "" },
{ "//", "" },
{ "/foo", "foo" },
{ "//foo", "foo" },
{ "a/b", NULL },
-#else
+#ifdef G_OS_WIN32
{ "\\", "" },
{ "\\foo", "foo" },
{ "\\\\server\\foo", "" },
g_assert (strcmp (string, "file") == 0);
g_free (string);
g_print ("ok\n");
+#ifdef G_OS_WIN32
+ string = g_path_get_basename ("/foo/dir/");
+ g_assert (strcmp (string, "dir") == 0);
+ g_free (string);
+ string = g_path_get_basename ("/foo/file");
+ g_assert (strcmp (string, "file") == 0);
+ g_free (string);
+ g_print ("ok\n");
+#endif
g_print ("checking g_path_get_dirname()...");
for (i = 0; i < n_dirname_checks; i++)
g_print ("ok\n");
+ if (g_get_charset (&string))
+ g_print ("current charset is UTF-8: %s\n", string);
+ else
+ g_print ("current charset is not UTF-8: %s\n", string);
+
#ifdef G_PLATFORM_WIN32
g_print ("current locale: %s\n", g_win32_getlocale ());
g_print ("GLib DLL name tested for: %s\n", glib_dll);
close (fd);
g_clear_error (&error);
+#ifdef G_OS_WIN32
+ strcpy (template, "zap/barXXXXXX");
+ fd = g_file_open_tmp (template, &name_used, &error);
+ if (fd != -1)
+ g_print ("g_file_open_tmp works even if template contains '/'\n");
+ else
+ g_print ("g_file_open_tmp correctly returns error: %s\n",
+ error->message);
+ close (fd);
+ g_clear_error (&error);
+#endif
+
strcpy (template, "zapXXXXXX");
fd = g_file_open_tmp (template, &name_used, &error);
if (fd == -1)