Reputation: 99
Given an arbitrary path path
and some other path base
to a directory, how can I get a new relative path from base
to the same object in file system as path
?
For example (relpath #p"~/foo" #p"~/bar/")
must give me #p"../foo"
. There is such a function in Julia, for example, which is also called relpath
. Is there anything like that in Common Lisp (either in the standard or as a third-party library)?
Upvotes: 3
Views: 814
Reputation: 883
I know the question is related to common lisp but as a hint there is a solution within emacs lisp. The emacs lisp function to return the relative path is file-relative-name.
Upvotes: -1
Reputation: 38809
If both paths exists, you can normalize them to an absolute pathname by calling truename
; then, since pathname directories are lists, you can easily find the longest common path and build a relative pathname with as many :up
elements as necessary to go from the second pathname to the first:
(defun rp (p1 p2)
(loop
for d1 on (pathname-directory (truename p1))
for d2 on (pathname-directory (truename p2))
while (string= (first d1) (first d2))
finally
(return
(make-pathname
:directory (append (list :relative)
(substitute :up t d2 :test (constantly t))
d1)
:defaults p1))))
For example, assuming "/tmp/foo" exists and "~" is "/home/user/":
> (rp "/tmp/foo" "~/")
#P"../../tmp/foo"
This should cover a lot of common use cases, but this has its limitations (no wildcard names, files must exist, and probably other corner cases)
Upvotes: 1
Reputation: 60014
The closest to what you are looking for is called enough-namestring
:
(enough-namestring "~/foo/bar/baz" "~/foo/")
==> "bar/baz"
Upvotes: 5