Subject: bug#57353: [PATCH] Fix parse-colon-path with UNC directory names

From: Eli Zaretskii <[email-masked]>
Date: Wed, 24 Aug 2022 17:15:53 +0300

> Cc: [email-masked]
> Date: Tue, 23 Aug 2022 16:21:17 +0300
> From: Eli Zaretskii <[email-masked]>
> 
> > From: Richard Copley <[email-masked]>
> > Date: Tue, 23 Aug 2022 12:34:02 +0100
> > 
> > A comment in `parse-colon-path' says:
> > 
> > ;; Previous implementation used `substitute-in-file-name'
> > ;; which collapse multiple "/" in front.  Do the same for
> > ;; backward compatibility.
> > 
> > However, `substitute-in-file-name' does not do that:
> > 
> > (substitute-in-file-name "//foo/a/b") // -> "//foo/a/b"
> 
> That is true, but:
> 
>   (substitute-in-file-name "///foo/a/b") => "//foo/a/b"
> 
> So it does collapse multiple "/", at least sometimes.  Moreover, the
> above is on MS-Windows, but on GNU/Linux:
> 
>   (substitute-in-file-name "///foo/a/b") => "/foo/a/b"
> 
> So (a) this is system-dependent, and (b) substitute-in-file-name does
> collapse multiple slashes, but preserves UNCs on MS-Windows.
> 
> Therefore, your patch needs some (minor) amendments.

Does the patch below give good results in your use cases?

diff --git a/lisp/files.el b/lisp/files.el
index 8596d9a..26730df 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -856,10 +856,16 @@ parse-colon-path
                 (if (equal "" f) nil
                   (let ((dir (file-name-as-directory f)))
                     ;; Previous implementation used `substitute-in-file-name'
-                    ;; which collapse multiple "/" in front.  Do the same for
-                    ;; backward compatibility.
-                    (if (string-match "\\`/+" dir)
-                        (substring dir (1- (match-end 0))) dir))))
+                    ;; which collapses multiple "/" in front, while
+                    ;; preserving double slash where it matters.  Do
+                    ;; the same for backward compatibility.
+                    (if (string-match "\\`//+" dir)
+                        (substring dir
+                                   (- (match-end 0)
+                                      (if (memq system-type
+                                                '(windows-nt 'cygwin 'ms-dos))
+                                          2 1)))
+                      dir))))
               (split-string spath path-separator)))))
 
 (defun cd-absolute (dir)