shamaz.mazum
shamaz.mazum

Reputation: 99

Get relative path in Common Lisp

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

Answers (3)

Markus Peröbner
Markus Peröbner

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

coredump
coredump

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

sds
sds

Reputation: 60014

The closest to what you are looking for is called enough-namestring:

(enough-namestring "~/foo/bar/baz" "~/foo/")
==> "bar/baz"

Upvotes: 5

Related Questions