aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mendler <mail@daniel-mendler.de>2023-01-05 13:02:52 +0100
committerDaniel Mendler <mail@daniel-mendler.de>2023-01-05 13:02:52 +0100
commitd289bf66f7d60d4c32ce2a64842dca00e98c2c4e (patch)
treedfc4656d640a490320d6e6f36fb74a6de362ef60
parentb467df10ca533c8940b27c3612f15acabdcd1de3 (diff)
Add file-name-split
-rw-r--r--compat-29.el27
-rw-r--r--compat-tests.el7
-rw-r--r--compat.texi14
3 files changed, 48 insertions, 0 deletions
diff --git a/compat-29.el b/compat-29.el
index 6ecf0fc..e7bdba5 100644
--- a/compat-29.el
+++ b/compat-29.el
@@ -483,6 +483,33 @@ The variable list SPEC is the same as in `if-let'."
;;;; Defined in files.el
+(compat-defun file-name-split (filename) ;; <OK>
+ "Return a list of all the components of FILENAME.
+On most systems, this will be true:
+
+ (equal (string-join (file-name-split filename) \"/\") filename)"
+ (let ((components nil))
+ ;; If this is a directory file name, then we have a null file name
+ ;; at the end.
+ (when (directory-name-p filename)
+ (push "" components)
+ (setq filename (directory-file-name filename)))
+ ;; Loop, chopping off components.
+ (while (length> filename 0)
+ (push (file-name-nondirectory filename) components)
+ (let ((dir (file-name-directory filename)))
+ (setq filename (and dir (directory-file-name dir)))
+ ;; If there's nothing left to peel off, we're at the root and
+ ;; we can stop.
+ (when (and dir (equal dir filename))
+ (push (if (equal dir "") ""
+ ;; On Windows, the first component might be "c:" or
+ ;; the like.
+ (substring dir 0 -1))
+ components)
+ (setq filename nil))))
+ components))
+
(compat-defun file-attribute-file-identifier (attributes) ;; <OK>
"The inode and device numbers in ATTRIBUTES returned by `file-attributes'.
The value is a list of the form (INODENUM DEVICE), where DEVICE could be
diff --git a/compat-tests.el b/compat-tests.el
index 605b58e..18306bd 100644
--- a/compat-tests.el
+++ b/compat-tests.el
@@ -731,6 +731,13 @@
(should-equal (file-name-concat "" "bar") "bar")
(should-equal (file-name-concat "" "") ""))
+(ert-deftest file-name-split ()
+ (should-equal (file-name-split "foo/bar") '("foo" "bar"))
+ (should-equal (file-name-split "/foo/bar") '("" "foo" "bar"))
+ (should-equal (file-name-split "/foo/bar/zot") '("" "foo" "bar" "zot"))
+ (should-equal (file-name-split "/foo/bar/") '("" "foo" "bar" ""))
+ (should-equal (file-name-split "foo/bar/") '("foo" "bar" "")))
+
(ert-deftest file-name-with-extension ()
(should-equal "file.ext" (file-name-with-extension "file" "ext"))
(should-equal "file.ext" (file-name-with-extension "file" ".ext"))
diff --git a/compat.texi b/compat.texi
index ffdadae..70b1041 100644
--- a/compat.texi
+++ b/compat.texi
@@ -2326,6 +2326,20 @@ generated by @code{file-attributes}.
@end defun
@c copied from lispref/files.texi
+@defun file-name-split filename
+This function splits a file name into its components, and can be
+thought of as the inverse of @code{string-join} with the appropriate
+directory separator. For example,
+
+@example
+(file-name-split "/tmp/foo.txt")
+ @result{} ("" "tmp" "foo.txt")
+(string-join (file-name-split "/tmp/foo.txt") "/")
+ @result{} "/tmp/foo.txt"
+@end example
+@end defun
+
+@c copied from lispref/files.texi
@defun file-name-parent-directory filename
This function returns the directory name of the parent directory of
@var{filename}. If @var{filename} is at the root directory of the