[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Fix 'dirname' and 'basename' on MS-Windows
From: |
Eli Zaretskii |
Subject: |
Fix 'dirname' and 'basename' on MS-Windows |
Date: |
Wed, 02 Jul 2014 19:13:05 +0300 |
These 2 functions don't deal correctly with Windows file names with
drive letters and with UNCs. The patch below fixes that.
Incidentally, isn't the line in scm_basename marked below wrong?
if (i == end)
{
if (len > 0 && is_file_name_separator (scm_c_string_ref (filename, 0)))
return scm_c_substring (filename, 0, 1);
else
return scm_dot_string; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
else
return scm_c_substring (filename, i+1, end+1);
It is responsible for the following strange results:
(basename ".foo" ".foo") => "."
(basename "_foo" "_foo") => "."
Also, isn't the following result wrong as well?
(basename "/") => "/"
I think all of these should return the empty string, "".
Here's the proposed patch for supporting Windows file names.
--- libguile/filesys.c~1 2014-06-29 16:13:30 +0300
+++ libguile/filesys.c 2014-07-02 14:03:08 +0300
@@ -448,6 +448,18 @@ is_file_name_separator (SCM c)
return 0;
}
+static int
+is_drive_letter (SCM c)
+{
+#ifdef __MINGW32__
+ if (SCM_CHAR (c) >= 'a' && SCM_CHAR (c) <= 'z')
+ return 1;
+ else if (SCM_CHAR (c) >= 'A' && SCM_CHAR (c) <= 'Z')
+ return 1;
+#endif
+ return 0;
+}
+
SCM_DEFINE (scm_stat, "stat", 1, 1, 0,
(SCM object, SCM exception_on_error),
"Return an object containing various information about the file\n"
@@ -1518,24 +1530,60 @@ SCM_DEFINE (scm_dirname, "dirname", 1, 0
{
long int i;
unsigned long int len;
+ /* Length of prefix before the top-level slash. Always zero on
+ Posix hosts, but may be non-zero on Windows. */
+ long prefix_len = 0;
+ int is_unc = 0;
+ unsigned long unc_end = 0;
SCM_VALIDATE_STRING (1, filename);
len = scm_i_string_length (filename);
+ if (len >= 2
+ && is_drive_letter (scm_c_string_ref (filename, 0))
+ && scm_is_eq (scm_c_string_ref (filename, 1), SCM_MAKE_CHAR (':')))
+ {
+ prefix_len = 1;
+ if (len > 2 && is_file_name_separator (scm_c_string_ref (filename, 2)))
+ prefix_len++;
+ }
+#ifdef __MINGW32__
+ if (len > 1
+ && is_file_name_separator (scm_c_string_ref (filename, 0))
+ && is_file_name_separator (scm_c_string_ref (filename, 1)))
+ {
+ is_unc = 1;
+ prefix_len = 1;
+ }
+#endif
i = len - 1;
- while (i >= 0 && is_file_name_separator (scm_c_string_ref (filename, i)))
+ while (i >= prefix_len
+ && is_file_name_separator (scm_c_string_ref (filename, i)))
--i;
- while (i >= 0 && !is_file_name_separator (scm_c_string_ref (filename, i)))
+ if (is_unc)
+ unc_end = i + 1;
+ while (i >= prefix_len
+ && !is_file_name_separator (scm_c_string_ref (filename, i)))
--i;
- while (i >= 0 && is_file_name_separator (scm_c_string_ref (filename, i)))
+ while (i >= prefix_len
+ && is_file_name_separator (scm_c_string_ref (filename, i)))
--i;
- if (i < 0)
+ if (i < prefix_len)
{
- if (len > 0 && is_file_name_separator (scm_c_string_ref (filename, 0)))
- return scm_c_substring (filename, 0, 1);
+ if (is_unc)
+ return scm_c_substring (filename, 0, unc_end);
+ else if (len > prefix_len
+ && is_file_name_separator (scm_c_string_ref (filename, prefix_len)))
+ return scm_c_substring (filename, 0, prefix_len + 1);
+#ifdef __MINGW32__
+ else if (len > prefix_len
+ && scm_is_eq (scm_c_string_ref (filename, 1),
+ SCM_MAKE_CHAR (':')))
+ return scm_c_substring (filename, 0, prefix_len + 1);
+#endif
else
return scm_dot_string;
}
@@ -1553,6 +1601,9 @@ SCM_DEFINE (scm_basename, "basename", 1,
#define FUNC_NAME s_scm_basename
{
int i, j, len, end;
+ /* Length of prefix before the top-level slash. Always zero on
+ Posix hosts, but may be non-zero on Windows. */
+ long prefix_len = 0;
SCM_VALIDATE_STRING (1, filename);
len = scm_i_string_length (filename);
@@ -1564,11 +1615,17 @@ SCM_DEFINE (scm_basename, "basename", 1,
SCM_VALIDATE_STRING (2, suffix);
j = scm_i_string_length (suffix) - 1;
}
+ if (len >= 2
+ && is_drive_letter (scm_c_string_ref (filename, 0))
+ && scm_is_eq (scm_c_string_ref (filename, 1), SCM_MAKE_CHAR (':')))
+ prefix_len = 2;
+
i = len - 1;
- while (i >= 0 && is_file_name_separator (scm_c_string_ref (filename, i)))
+ while (i >= prefix_len
+ && is_file_name_separator (scm_c_string_ref (filename, i)))
--i;
end = i;
- while (i >= 0 && j >= 0
+ while (i >= prefix_len && j >= 0
&& (scm_i_string_ref (filename, i)
== scm_i_string_ref (suffix, j)))
{
@@ -1577,12 +1634,20 @@ SCM_DEFINE (scm_basename, "basename", 1,
}
if (j == -1)
end = i;
- while (i >= 0 && !is_file_name_separator (scm_c_string_ref (filename, i)))
+ while (i >= prefix_len
+ && !is_file_name_separator (scm_c_string_ref (filename, i)))
--i;
if (i == end)
{
- if (len > 0 && is_file_name_separator (scm_c_string_ref (filename, 0)))
- return scm_c_substring (filename, 0, 1);
+ if (len > prefix_len
+ && is_file_name_separator (scm_c_string_ref (filename, prefix_len)))
+ return scm_c_substring (filename, 0, prefix_len + 1);
+#ifdef __MINGW32__
+ else if (len > prefix_len
+ && scm_is_eq (scm_c_string_ref (filename, 1),
+ SCM_MAKE_CHAR (':')))
+ return scm_c_substring (filename, 0, prefix_len + 1);
+#endif
else
return scm_dot_string;
}
- Re: Windows file name separators, (continued)
- Re: Windows file name separators, Eli Zaretskii, 2014/07/01
- Re: Windows file name separators, Ludovic Courtès, 2014/07/01
- Re: Windows file name separators, Eli Zaretskii, 2014/07/02
- Re: Windows file name separators, Ludovic Courtès, 2014/07/02
- Re: Windows file name separators, Ludovic Courtès, 2014/07/02
- Re: Windows file name separators, Eli Zaretskii, 2014/07/03
- Re: Windows file name separators, Ludovic Courtès, 2014/07/03
- Re: Windows file name separators, Eli Zaretskii, 2014/07/03
- Re: Windows file name separators, Mark H Weaver, 2014/07/07
- Re: Windows file name separators, Eli Zaretskii, 2014/07/07
- Fix 'dirname' and 'basename' on MS-Windows,
Eli Zaretskii <=
- Re: Fix 'dirname' and 'basename' on MS-Windows, Ludovic Courtès, 2014/07/09
- Re: Fix 'dirname' and 'basename' on MS-Windows, Eli Zaretskii, 2014/07/09
- Provide reasonable stack limit on MS-Windows, Eli Zaretskii, 2014/07/02
- Re: Provide reasonable stack limit on MS-Windows, Ludovic Courtès, 2014/07/02
- Re: Provide reasonable stack limit on MS-Windows, Eli Zaretskii, 2014/07/03
- Bug in scm_getaffinity, Eli Zaretskii, 2014/07/02
- Re: Bug in scm_getaffinity, Ludovic Courtès, 2014/07/02
- Re: Bug in scm_getaffinity, Eli Zaretskii, 2014/07/03