branch: externals/compat commit d289bf66f7d60d4c32ce2a64842dca00e98c2c4e Author: Daniel Mendler <m...@daniel-mendler.de> Commit: Daniel Mendler <m...@daniel-mendler.de>
Add file-name-split --- compat-29.el | 27 +++++++++++++++++++++++++++ compat-tests.el | 7 +++++++ compat.texi | 14 ++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/compat-29.el b/compat-29.el index 6ecf0fca9d..e7bdba5dc3 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 605b58e82c..18306bda25 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 ffdadaee99..70b1041252 100644 --- a/compat.texi +++ b/compat.texi @@ -2325,6 +2325,20 @@ generated by @code{file-attributes}. @xref{File Attributes,,,elisp}. @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