Here's the final solution (based on the previous two answers):
(defun abspath
(path-string)
(uiop:unix-namestring
(uiop:merge-pathnames*
(uiop:parse-unix-namestring path-string))))
uiop:parse-unix-namestring
converts the string argument to a pathname, replacing .
and ..
references; uiop:merge-pathnames*
translates a relative pathname to absolute; uiop:unix-namestring
converts the pathname back to a string.
Also, if you know for sure what kind of file the path points to, you can use either:
(uiop:unix-namestring (uiop:file-exists-p path))
or
(uiop:unix-namestring (uiop:directory-exists-p path))
because both file-exists-p
and directory-exists-p
return absolute pathnames (or nil
, if file does not exist).
UPDATE:
Apparently in some implementations (like ManKai Common Lisp) uiop:merge-pathnames*
does not prepend the directory part if the given pathname lacks ./
prefix (for example if you feed it #P"main.c"
rather than #P"./main.c"
). So the safer solution is:
(defun abspath
(path-string &optional (dir-name (uiop:getcwd)))
(uiop:unix-namestring
(uiop:ensure-absolute-pathname
(uiop:merge-pathnames*
(uiop:parse-unix-namestring path-string))
dir-name)))
*default-pathname-defaults*
is empty there). OK. But how to resolve..
references -cl-fad:canonical-pathname
doesn't work? – Aretina