From: Kaelin Colclasure
Subject: Franz ACL (defsystem ... (:default-pathname ...) ...)
Date: 
Message-ID: <9DgD3.59$4z.9417@newsin1.ispchannel.com>
Greetings,

I'm curious if there's a simple way to parameterize the argument in a
(:default-pathname ...) form to be "the directory from which the file
that contains this form is being loaded." [Note that this is not the
same thing as the "current directory."] I confess I haven't exactly
groked CL pathnames -- but my shallow impression leads me to presume
that they do not address this particular bit of functionality.

-- Kaelin

From: Arthur Lemmens
Subject: Re: Franz ACL (defsystem ... (:default-pathname ...) ...)
Date: 
Message-ID: <37DE038B.56A21BD8@simplex.nl>
Kaelin Colclasure wrote:
> 
> I'm curious if there's a simple way to parameterize the argument in a
> (:default-pathname ...) form to be "the directory from which the file
> that contains this form is being loaded." 

I know nothing about Franz' DEFSYSTEM, but *LOAD-PATHNAME* will give you
the pathname of the file being loaded. The rest should be easy.

--
Arthur Lemmens
From: Howard R. Stearns
Subject: Re: Franz ACL (defsystem ... (:default-pathname ...) ...)
Date: 
Message-ID: <37E0045B.9A87D6C2@elwood.com>
Kaelin Colclasure wrote:
> 
> Greetings,
> 
> I'm curious if there's a simple way to parameterize the argument in a
> (:default-pathname ...) form to be "the directory from which the file
> that contains this form is being loaded." [Note that this is not the
> same thing as the "current directory."] I confess I haven't exactly
> groked CL pathnames -- but my shallow impression leads me to presume
> that they do not address this particular bit of functionality.
> 
> -- Kaelin

(Simple questions....)


I'm not certain specifically about ACL, but many defsystem
implementations do not evaluate their arguments.  More precisely, the
subforms given within the defsystem form are not evaluated but are
instead treated as literal objects.  When this is true, you can't just
do (:default-pathname (merge-pathname ... ...)).  Of course, these
subforms are created by the lisp reader, which provides the #. READER
macro.

Thus, if this does turn out to be a limitation of Allegro defsystem,
then you can do something like:

 (defsystem ... (:default-pathname #.(merge-pathnames
"whatever/you/like" *load-pathname*)) ...

Some other issues involves matching up the two arguments to
merge-pathnames.  *load-truename* is specified by ANSI to be a physical
pathname, so you should be able to use a physical pathname namestring as
the first argument and *load-truename* as the second.  Unfortunately,
this isn't very portable.  

*load-pathname* will be a logical pathname if the defsystem form was
loaded from a file by opening the file with a logical pathname.  For
example, suppose you load the defsystem form with (load
"my-stuff:system-name;sysdcl.lisp").  Then *load-pathname* will be that
logical pathname.  Some defsystem implementations, however, provide
automatic means to find the defsystem definition for you, and these
automatic means may or may not preserve the logical pathname by the time
it gets to opening the sysdcl file.

Anyway, if *load-pathname* is a logical pathname, then you can use it as
the second argument to merge-pathnames, and a logical pathname
namestring as the first argument. This would give you platform
independence if you could at least be sure that your favorite
implementation had the same implementation of defsystem on all
platforms.  If the second argument to merge-pathnames is logical and the
first argument is a physical pathname namestring, then it is up to your
implementation to decide how to parse and merge the string.  

One way you might try to avoid this nonsense, if it is an issue for you,
is to use something like #.(make-pathname :directory '(:relative "foo")
:defaults *load-pathname*).  Again, though, you may still have some
problems with underspecified :host behavior, so you might decide you
need something like #.(make-pathname :directory '(:relative "foo") :host
(pathname-host *load-pathname*) :defaults *load-pathname*)).

Also, some (older?) implementations of Allegro have (had?) the behavior
that *load-pathname*/*load-truename* was based on the argument given to
load rather than the merged pathname that is actually used to open the
file.  In this case, you need to further merge
*load-pathname*/*load-truename* against *default-pathname-defaults*!

Finally, how do you properly specify a directory name anway?  Must you
include a trailing ;, :, >, /, or \ character?  Must you NOT include it?

Clearly, this is getting silly and it would be far better for the
implementation to document how :default-pathame is merged.  Failing
that, I find it convenient to have a MAKE-PATHNAME-DIRECTORY function
that in this case, is used instead of MERGE-PATHNAMES or MAKE-PATHNAME. 
I also find it convenient for other purposes.

Here's the code I've been using, which hasn't been beat on quite as much
as I would like:

;;; The implementation of this function is not portable in principle,
;;; but in practice it covers things pretty well. 

(defmethod PATHNAME-BASE ((pathname pathname) &key (case :local))
  "Returns the pathname base as a string. E.g., name.type.version."
  (ecase case
    (:local (file-namestring pathname))
    (:common (let ((version (pathname-version pathname)))
	       (format nil (formatter ··@[~a~]·@[.~a~]·@[.~a~]")
		       (pathname-name pathname :case :common)
		       (pathname-type pathname :case :common)
		       (unless (symbolp version) version))))))
  
;;; This needs to use :case :common throughout in case thing and
;;; default are different kinds of pathnames (e.g., unix and logical).
;;; Implementationally, it looks like (make-directory-pathname
;;; "../foo/bar/") and (make-directory-pathname '(:relative :back
;;; "FOO" "BAR")) ought to be two separate functions, but from the
;;; callers point of view, they look like they're close enough that we
;;; want to be able to use the same function.  We need the latter case
;;; because when you include all the defaulting and fixes for broken
;;; implementations of *load-pathname*, this isn't all that easy to do
;;; by hand.

(defun MAKE-DIRECTORY-PATHNAME (thing
				&optional
				(default
				  #-allegro-v4.1 *load-pathname*
				  #+allegro-v4.1 ;Shame on them
				  (merge-pathnames *load-pathname*)))
  "Converts THING into a directory pathname with null name, type, and
 version.  Relative directories in THING are merged against DEFAULT,
 which defaults to *load-pathname*, but is always ORed against
 *default-pathname-defaults*. THING can also be a :common case
 pathname component list, which is merged against DEFAULT."

  ;; Note that *load-pathname* will be NIL outside of LOAD, or the
  ;; DEFAULT argument might explicitly be NIL.
  (let* ((default (or default *default-pathname-defaults*))
	 (default-dir (pathname-directory default :case :common)))
    (if (listp thing)
	(make-pathname :name nil :type nil :version nil
		       :directory (merge-directories thing default-dir)
		       :case :common
		       :defaults default)
	(let* ((pathname (parse-namestring thing nil default))
	       (terminal (pathname-base pathname :case :common))
	       (directory (pathname-directory pathname :case :common)))
	  (make-pathname :name nil :type nil :version nil
			 :directory (merge-directories
				     (if (and terminal
					      (not (string= terminal "")))
					 (append (or directory
						     '(:relative))
						 (list terminal))
					 directory)
				     default-dir)
			 :case :common
			 :defaults pathname)))))

(defun merge-directories (p d &optional truename-style-p)
  ;; When generating a truename, :UP should be merged out as though it
  ;; were :BACK. 
  (if (eq (car p) :relative)
      (let ((results (cons (or (pop d) :relative) nil)))
	(labels ((backp (dir)
		   (or (eq dir :back)
		       (and truename-style-p (eq dir :up))))
		 (add (dir)
		   (if (and (backp dir)
			    (cdr results)
			    (not (backp (car results))))
		       (pop results)
		     (push dir results))))
	  (dolist (dir d) (add dir))
	  (dolist (dir (cdr p)) (add dir)))
	(nreverse results))
    (or p d)))
From: Thomas A. Russ
Subject: Re: Franz ACL (defsystem ... (:default-pathname ...) ...)
Date: 
Message-ID: <ymi4sgth455.fsf@sevak.isi.edu>
(... :default-pathname
     (make-pathname :host (pathname-host *load-pathname*)
                    :device (pathname-device *load-pathname*)
                    :directory (pathname-directory *load-pathname*))
   )

By copying the HOST and DEVICE fields you get better portability.  In
particular, Windows-based systems often need the device field copied in
order to have the Drive numbers done properly.

-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu