Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Joining a series of paths components in common lisp

How do I join a series of path components in common lisp?

In python, I can do,

`os.path.join("/home/", username, "dira", "dirb", "dirc");`

What would be the equivalent in common lisp?

Of course I can write my own function, but I suspect I should be able to use something built-in.

like image 657
ealfonso Avatar asked Jan 20 '26 17:01

ealfonso


1 Answers

If you insist on using strings to represent pathnames, then there seems to be no built-in solution except rolling your own.

(defun join-strings (list &key (separator "/") (force-leading nil))
  (let* ((length (length list))
         (separator-size (length separator))
         (text-size (reduce #'+ (mapcar #'length list) :initial-value 0))
         (size (+ text-size (* separator-size (if force-leading length (1- length)))))
         (buffer (make-string size)))
    (flet ((copy-to (position string)
             (loop
               :with wp := position
               :for char :across string 
               :do (setf (char buffer (prog1 wp (incf wp))) char)
               :finally (return wp))))
      (loop
        :with wp := 0
        :for string :in list
        :do (when (or force-leading (plusp wp)) (setf wp (copy-to wp separator)))
            (setf wp (copy-to wp string)))
      buffer)))

(join-strings '("home" "kurt" "source" "file.txt") :force-leading t)
==> "/home/kurt/source/file.txt"

However, if you can use pathnames, then you could, for example, do:

(merge-pathnames #P"subdir1/subdir2/file.type" #P"/usr/share/my-app")
==> #P"/usr/share/my-app/subdir1/subdir2/file.type"

The pathname API also provides functions to manipulate pathnames symbolically, extract the components of a pathname, etc.:

(pathname-directory #P"subdir1/subdir2/file.type")
==> '(:relative "subdir1" "subdir2")

(pathname-name #P"subdir1/subdir2/file.type")
==> "file"

(pathname-type #P"subdir1/subdir2/file.type")
==> "type"

(make-pathname :name "file" :type "type" :directory '(:relative "subdir1" "subdir2"))
==> #P"subdir1/subdir2/file.type"

In particular, the directory component of a pathname is represented as a list, and thus, you can use the full set of list handling functions to derive directory values from others:

(make-pathname :directory (append '(:absolute "usr" "share") '("more" "stuff"))
               :name "packages" :type "lisp")
like image 117
Dirk Avatar answered Jan 22 '26 10:01

Dirk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!