;;; .EnTete "Le-Lisp (c) version 15.2" " " "Logical Pathnames"
;;; .EnPied "pathname.ll" "%" " "
;;;
;;; .SuperTitre "Fonctions sur les Noms de fichier logiques"
;;; .Auteur "Michel Dana, ENST"
;;;
;;; .Centre "*****************************************************************"
;;; .Centre " Ce fichier est en lecture seule hors du projet ALE de l'INRIA.  "
;;; .Centre " Il est maintenu par ILOG SA, 2 Avenue Gallie'ni, 94250 Gentilly "
;;; .Centre " (c) Le-Lisp est une marque de'pose'e de l'INRIA                 "
;;; .Centre "*****************************************************************"

;;; .Centre "$Header: path.ll,v 1.12 88/12/13 18:10:40 neidl Exp $"

;;; This file contains the code which handles the virtual pathname
;;; scheme for Le-Lisp. It contains also the special handlers for the
;;; VMS and UNIX operating systems 


;;; Notice for the implementors of Le-Lisp on other operating systems:
;;; 
;;; if you want to extend this module for an other O.S., which name
;;; as the result of (system) is `newsys`, you have to write a driver for
;;; your OS.  This driver must contain the following functions, which
;;; must be explicitely exported bye COMPLICE.

;;; #:newsys:namestring : this function takes a pathname as argument
;;; and  evaluates to the external name of the pathname for the O.S.

;;; #:newsys:pathname :  this function takes an external string as an
;;; argument and gives a pathname 


;;; #:newsys:homedir-pathname : This function has no argument and
;;; gives the pathname which represents the "home-directory" of the
;;; current user . If there is no such facility in the current O/S,
;;; this function gives a valid directory.


;;; #:newsys:directory-namestring: This function accepts a pathname as
;;; an argument and gives the external string which represents the
;;; directory part of the pathname 


;;;  #:newsys:temporary-file-pathname : This function takes a string
;;;  as an argument, and builds a pathname which should be a temporary
;;;  file   pathname, as /tmp/foo for UNIX

;;; #:newsys:file-namestring : this function takes a pathname as
;;; argument and gives the external string representing the name type
;;; et version fields of the pathname. If your OS doesn't provide ant
;;; mechanism for version support, you are supposed to emulate it in
;;; the most convenient way.



;;; #:newsys:host-namestring : takes a pathname as argument, and gives
;;; the external string representing the host on which resides the
;;; file... if your host doesn't support network access , you must
;;; return the empty string


;;; #:newsys:device-namestring : takes a pathname as argument and 
;;; returns the external string which represents the physical device 
;;; on which the file system resides. If this facility doesn't exist,
;;; returns the empty string

;;; #:newsys:current-directory : this function will get/set the
;;; working directory of  Lisp process, and also that of the
;;; shell/process (if there is one)

;;; #:newsys:wild : this function will return the list of all pathname
;;; in the file systeme, which can be found according to the pattern
;;; which is the argument .



;;;  You may also write a function #:newsys:check-pathname which will
;;;  check that its argument is a valid pathname for your operating
;;;  system . (i.e. No special character,etc..) 
;;;  this function returns () if the syntax is illegal




 (unless (>= (version) 15.2)
	 (error 'load 'erricf 'pathname))

(setq #:sys-package:colon 'pathname)
(add-feature 'pathname)



;;; the mechanism which calls easily new operating systems
;;;
;;;
 (dmd to-system (cmd . larg)
      `(funcall (getfn (system) ,cmd ()) ,@larg))
;;;
;;;

; 1) definition of a  pathname

(defstruct pathname
           host		; name of the host of the file-system
	   device       ; physical device
           directory    ; list of directories
	   name         ; file name
           type         ; extension 
           version      ; version number, or ()

 )

;;;1) Let's convert a pathname in an external string


(de namestring (p)
    (unless (pathnamep p) (error 'namestringname 'ERRBPA p))
    (cond
     (#:system:unixp (#:unix:namestring p))
     ((eq (system) 'vaxvms) (#:vaxvms:namestring p))
     (t (to-system 'namestring p))
     )) 

;;1.1) Unix Case.. actually no hosts or device .... poor man's
;;     Operating system


(de #:unix:namestring (p)
    (catenate 
     (#:unix:directory-namestring p)
     (#:unix:file-namestring p)))

;;1.2) the same for VMS.. that's a Real Operating System

(de #:vaxvms:namestring (p)
    (catenate
     (#:vaxvms:host-namestring p)
     (#:vaxvms:device-namestring p)
     (#:vaxvms:directory-namestring p)
     (#:vaxvms:file-namestring p)))

;;; The predicate for pathnames 

(de pathnamep (p)
    (eq (type-of p ) 'pathname)))
    

;;; the get function in the common-lisp flavour

(de pathname-host(p)
    (unless (pathnamep p) (setq p (pathname p)))
    (:host p)))

(de pathname-device (p)
    (unless (pathnamep p) (setq p (pathname p)))
    (:device p)))

(de pathname-directory (p)
    (unless (pathnamep p) (setq p (pathname p)))
    (:directory p)))

(de pathname-name (p)
    (unless (pathnamep p) (setq p (pathname p)))
    (:name p)))

(de pathname-type (p)
    (unless (pathnamep p) (setq p (pathname p)))
    (:type p)))

(de pathname-version (p)
    (unless (pathnamep p) (setq p (pathname p)))
    (:version p)))




;;;2)  and now, let's convert an external namestring into a pathname..
;;;    that is  more difficult 

(de pathname(f)
    (cond 
     ((equal f "")(new 'pathname))
     (#:system:unixp (#:unix:pathname f))
     ((eq (system) 'vaxvms) (#:vaxvms:pathname f))
     (t (to-system 'pathname f ))))                


;2.1)  UNIX case

;;; if the string begins with a /, it is an absolute pathname.
;;;                             ../ , you want to go upward in the hierarchy
;;;                             ./ or nothing, it is relative to the
;;;                             current directory. if it contains /,
;;;                             it starts with a directory part,
;;;                             otherwise there is only a filename
;;;                             . : there is only the type field
;;;                             ..N : there is only the version number
;;;                             


(de #:unix:pathname (s)
    (let (( p (new 'pathname))
	  (s1 (string s))
	  (s2 ())
	  (l ()))
      (if (eq (slen s1) 0) p		; empty path
	(cond 
	 (( eq (sref s1 0) #//) (setq s1 (substring s1 1)))
	 (( eq (index "../" s1) 0) (setq s1 (substring s1 3))
	  (:directory p (ncons ':up)))
	 (( eq (index "./" s1) 0) (setq s1 (substring s1 2))
	  (:directory p (ncons ':current)))
	 (( index "/" s1) (:directory p (ncons ':current))))

	;; we have parsed the beginning of the string , and we do
	;; actually know if we are an absolute or relative
	;; specification...
	;; we must now parse the directory specification

	(while (setq l (index "/" s1))
	  (cond ( (equal (setq s2 (substring s1 0 l)) "..")(setq s2 ':up))
		( (equal s2 ".") (setq s2 ':current))
		( (equal s2 "*") (setq s2 ':wild)))
	  (:directory p  (cons  s2 (:directory p)))
	  (setq s1 (substring s1 (add1 l))))
	(:directory p(nreverse (:directory p)))
     
	;; here, there are  only the name, type and version fields left

	(unless (or (eq (slen s1) 0)
		    (eq (sref s1 0) #/.))
		(setq s2
		      (substring s1 0
				 (setq l (or (index "." s1)
					     (slen s1)))))
		(:name p (if (equal s2 "*") ':wild s2))
		(setq s1(substring s1 l)))
					;the type field
	(unless (or 
		 (eq (slen s1) 0)
		 (eq (slen (setq s1 (substring s1 1))) 0))
		(setq s2
		      (substring s1 0
				 (setq l (or (index "." s1)
					     (slen s1)))))
		(:type p
		       (cond ((equal s2 "*") ':wild)
			     ((eq l 0) ())
			     (t s2)))
		(setq s1 (substring s1 l)))
	;; the version field...
	;; a number or *

	(unless (or (eq (slen s1)0)(eq (slen (setq s1 (substring s1 1)))0))
		(setq s2 (stratom (slen s1) s1 ()))
		(:version p
			  (cond ((fixp s2) s2)
				((equal s1 "*") ':wild)
				((not (fixp s2))
				 (when *portable-pathname*
				       (printerror 'pathname
						   "Version n'est pas un numerique"
						   s2))
				 ()))))
	p)))


;;;2.2 the same for VMS
;;;
;;;the syntaxe is much more complex

    (de #:vaxvms:pathname (s)
	(let ((p (new 'pathname))
	      (s1 (string s))
	      (l ()))

	  ;;a- is it a decnet file ?
	  (when (setq l (index "::" s1 ))
		(:host p (substring s1 0 l))
		(setq s1 (substring s1 (add l 2))))

	  ;;b- on which physical device ?
	  (when (setq l (index ":" s1 ))
		(:device p (substring s1 0 l))
		(setq s1 (substring s1 (add1 l))))

	  ;;c- is there a directory part ?

	  (when (and (neq (slen s1) 0)(eq (sref s1 0) #/[))
		(setq s1 (substring s1 1))
		(while (index "]" s1)
		  (if (setq l (scanstring s1 ".]"))
		      (:directory p 
				  (cons (substring s1 0 l) (:directory p)))
		    (error '#:vaxvms:pathname 'ERRSXT s))
		  (setq s1 (substring s1 (add1 l))))
		(:directory p (nreverse (:directory p))))

	  ;;e- is there a file name ?

	  (if (or (eq (slen s1)0)
		  (eq (sref s1 0) #/.))
	      (setq s1 (substring s1 1))
	    (:name p
		   (substring s1 0
			      (if (setq l (index "." s1 )) l (setq l (slen s1)))))
	    (setq s1 (substring s1 (min (add1 l) (slen s1)))))
	  ;;e- is there a type ?
	  (unless (eq (slen s1) 0)
		  (:type p
			 (substring s1 0
				    (if (setq l (index ";" s1 )) l (setq l (slen s1)))))
		  (setq s1 (substring s1 (min (add1 l)(slen s1)))))
	  ;;f- is there a version ?
	  (unless (eq (slen s1) 0)
		  (:version p
			    (or (fixp (stratom (slen s1) s1 ()))
				())))

;;;	  ;; lets check its a valid syntax
;;;	  (if   (#:vaxvms:pathname-check p)
	  p
;;;	    (error 'pathname ERRSXT p)))
	  ))))))



;;; Now, some funny functions...
;;; let'us give a standard way to get the user home-directory.. this
;;; will be useful for the layered product, as DEC says...


(de user-homedir-pathname()
    (cond 
     (#:system:unixp (#:unix:pathname(catenate (getenv "HOME") "/")))
     ((eq (system) 'vaxvms) (#:vaxvms:pathname(#:vaxvms:trlnm "sys$login:")))
     (t (to-system 'homedir-pathname)))))


;;; be careful for the VMS guys. The name you get can't be
;;; concateneted with others... you'll have to wait until there is a
;;; real (#:vaxvms:trlnm) function....

;;;
;;; now, let'us build the run-time control file for a layered product 

(de control-file-pathname (appli)
    (let ((s (string appli))
	  (p (user-homedir-pathname)))
      (when (gt (slen s) 12) (setq s (substring s 0 11)))
      (:type  p (catenate s "rc"))
      p)))))

;;;  here is a standard way to create temporary files...
;;;  this is mainly useful for test programms, and other utilities..

;;
(de temporary-file-pathname (seed)
    (cond 
     (#:system:unixp (pathname (catenate"/tmp/" seed)))
     ((eq (system) 'vaxvms)
      (pathname (catenate "sys$scratch:" seed)))
     (t (to-system 'temporary-file-pathname seed))))


;;; a bit more complex : a function that checks that a pathname
;;; adheres to the syntaxe of all operating systems which support
;;; le-lisp... of course, this is not a finite problem...  so there is
;;; no guarantee, but just a help to write portable code...

;;; first the fields device and host are not supported by all O.S and
;;; have a very special syntax and semantic, depending on the O.S.. so
;;; no check needs to be performed for these fields..


(de #:bsd:pathname-check (p) t)
(de #:sys5:pathname-check(p) 
    (let ((l (mcons (:type p)(:name p)(:directory p))))
      (every (lambda(x) (le (slen x) 14)) l)
      )))


(de #:aegis:pathname-check(p) t)


(de #:vaxvms:pathname-check (p)
    (let ((l (mcons (:type p)(:name p) (:directory p))))
      (and
       ;;no more than 8 subdirectories
       (le (length (:directory p)) 8)
       ;;only  32 characters each
       (every (lambda(x) (if x (le (slen x) 32) t)) l )
       ;;many characters are illegal...
       (every
	(lambda(x)
	  (not (spanstring x 
			   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890←-$")))
	l)
       ;;version is a number
       (if (:version p) (fixp (:version p))
	 t)
       ))))))


(de portable-pathname-p (p)
    (with ((outchan t))
	  (unless (pathnamep p)
		  (error 'portable-pathnamep "N'est pas un pathname" p))
	  (when (or (:host p)(:device p))
		(printerror 'portable-pathnamep 
		       " Attention les champs Host ou Device ne sont pas vides"
		       (list (:host p)  (:device p))))
	  (unless (#:vaxvms:pathname-check p) 
		  (printerror 'portable-pathnamep 
			 "Pas une specification VMS" p))
	  (unless (#:bsd:pathname-check p) 
		  (printerror 'portable-pathnamep 
			 "Pas une specification  BSD" p))
	  (unless (#:sys5:pathname-check p) 
		  (print 'portable-pathnamep 
			 "Pas une specification SYS5" p))
	  (unless (#:aegis:pathname-check p)
		  (print 'portable-pathnamep 
			 "Pas une specification AEGIS" p))
	  ))

;;; a method to print pathames in a fair way
;;;default printing is
;;; #p:the-string-in-the-os-syntaxe, or the typed vector syntax...

(de :prin (p)
    (if #:system:print-for-read
	(progn
	  (let (( #:system:print-for-read ()))
	    (prin ":#[ "))
	  (mapvector
	   (lambda(x)
	     (prin x)
	     (princn #/ ))
	   p)
	  (princn #/] ))
      (prin "#p"""  (namestring p) """")) 
    p)

(defsharp p ()
  (ncons (pathname(read))))

(defsharp u ()
  (ncons (#:unix:pathname (read))))

;;; default values for parsing and merging as defined bye
;;; CLtL

(defvar *default-pathname-defaults* #p"")
(defvar *portable-pathname* ())


(de make-pathname liste-of-elements
    (let ((p (new 'pathname)))
      (:host p 
	     (or (car liste-of-elements) 
		 (:host *default-pathname-defaults*)))
      (:device p
	       (or (cadr liste-of-elements)
		   (:device *default-pathname-defaults*)))
      (:directory p
		  (or (caddr liste-of-elements)
		      (:directory *default-pathname-defaults*)))
      (:name p
	     (or (cadddr liste-of-elements)
		 (:name *default-pathname-defaults*)))
      (:type p
	     (or (car (cddddr liste-of-elements))
		 (:type *default-pathname-defaults*)))
      (:version p
		(or (fixp (cadr (cddddr liste-of-elements)))
		    (:version  *default-pathname-defaults*)))
      p)))

           
(de file-namestring (p)
    (if (pathnamep p)
	(cond
	 (#:system:unixp (#:unix:file-namestring p))
	 ((eq (system) 'vaxvms) (#:vaxvms:file-namestring p))
	 (t( to-system 'file-namestring p)))
      (error 'file-namestring ERRBPA p)))

(de directory-namestring (p)
    (if (pathnamep p)
	(cond
	 (#:system:unixp (#:unix:directory-namestring p))
	 ((eq (system) 'vaxvms) (#:vaxvms:directory-namestring p))
	 (t (to-system 'directory-namestring p)))
      (error 'directory-namestring ERRBPA p)))

(de host-namestring (p)
    (if (pathnamep p)
    (cond
     (#:system:unixp (#:unix:host-namestring p))
     ((eq (system) 'vaxvms) (#:vaxvms:host-namestring p))
     (t(to-system 'host-namestring p)))
    (error 'host-namestring ERRBPA p)))
 
(de device-namestring (p)
    (if (pathnamep p)
	(cond
	 (#:system:unixp (#:unix:device-namestring p))
	 ((eq (system) 'vaxvms) (#:vaxvms:device-namestring p))
	 (t (to-system 'device-namestring p)))
      (error 'device-namestring ERRBPA p)))



(de #:unix:host-namestring (p)
    "")
(de #:unix:device-namestring (p) "")

(de #:unix:directory-namestring (p)
     (ifn (:directory p) ""
     (let ((q "/")(y (if (stringp (car (:directory p))) "/" "")))
       (mapc (lambda(x) (setq y
                        (catenate y 
                          (cond ((stringp x) x)
                                ((eq x ':up) "..")
                                ((eq x ':wild) "*")
                                ((eq x ':current) "."))
                          q)))
                      (:directory p))
                       y)))

(de #:unix:file-namestring (p)
    (catenate
     (cond ((stringp (:name p)))
	   ((not (:name p)) "")
	   ((eq (:name p) ':wild) "*"))
     (when (:type p) ".")
     (cond ((stringp (:type p))(:type p))
	   ((not (:type p))"")
	   ((eq (:type p) ':wild) "*"))
     (when (:version p) ".")
     (cond ((fixp (:version p))(string (:version p)))
	   ((eq (:version p) ':wild) "*")
	   (t ""))))

(de #:vaxvms:host-namestring (p)
    (if (:host p)
	(catenate (:host p) "::")
      ""))
(de #:vaxvms:device-namestring(p)
    (if (:device p)
	(catenate (:device p) ":")
      ""))

(de #:vaxvms:directory-namestring (p)
    (let ((y "["))
      (if   (:directory p)
	  (progn 
	    (mapc (lambda(x) 
		    (setq y 
			  (cond ((stringp x)
				 (if (or (eq (sref y (sub1 (slen y))) #/[)
					 (eq (sref y (sub1 (slen y))) #/.))
				     (catenate y x)
				   (catenate y "." x)))
                                        
				((eq x ':wild)
                                 (if (or (eq (sref y (sub1 (slen y))) #/[)
					 (eq (sref y (sub1 (slen y))) #/.))
				     (catenate y "*")
				   (catenate y ".*")))
				((eq x ':current) (catenate y "."))
				((eq x ':up) (catenate y "-")))))
		  (:directory p))
	    (if (eq (sref y (sub1 (slen y))) #/.)
                (sset y (sub1 (slen y)) #/])
	      (setq y (catenate y "]")))
            (if (equal y "[]") "" y))
	())))

(de #:vaxvms:file-namestring (p)
    (catenate
     (cond
      ((stringp (:name p)) (:name p))
      ((eq (:name p) ':wild) "*")
      ((not (:name p)) "")
      (t (error 'file-namestring 'ERRSXT (:name p))))
     (if (:type p) "." "")
     (cond
      ((stringp (:type p)) (:type p))
      ((eq (:type p) ':wild) "*")
      ((not (:type p)) "")
      (t (error 'file-namestring 'ERRSXT (:type p))))
     (if (:version p) ";" "")
     (string (:version p))))


(de merge-pathnames ( p default)
    (let ((p1 (new 'pathname)))
      (:host p1
	     (or (:host p)
		 (:host default)))
      (:device p1
	       (or (:device p)
		   (:device default)))
      (:directory p1
		  (or (:directory p)
		      (:directory default)))
      (:name p1
	     (or (:name p)
		 (:name default)))
      (:type p1
	     (or (:type p)
		 (:type default)))
      (:version p1
		(or (:version p)
		    (:version default)))
      p1))


(de enough-namestring (p . defaults)
    (cond
     ((not  defaults ) (setq defaults *default-pathname-defaults*))
     ((not (pathnamep (setq  defaults (car defaults))))
      (setq defaults (pathname defaults))))
    (let ((p1 (new 'pathname)))
      (unless (equal (:host defaults)
		     (:host p))
	      (:host p1 (:host p)))
      (unless (equal (:device defaults)
		     (:device p))
	      (:device p1 (:device p)))
      (unless (equal (:directory defaults)
		     (:directory p))
	      (:directory p1 (:directory p)))
      (unless (equal (:name defaults)
		     (:name p))
	      (:name p1 (:name p)))
      (unless (equal (:type defaults)
		     (:type p))
	      (:type p1 (:type p)))
      (unless (equal (:version defaults)
		     (:version p))
	      (:version p1 (:version p)))
      (namestring p1)))))
 
             

;;; this part of the code handles the true pathname facility of CLtL..
;;; The hidden mechanism may be different , depending on the operating
;;; system . UNIX has environnment variables which may be put as the
;;; beginning of a word.. VMS has logfical name translations.. etc...

( de true-pathname (p)
     ;; P is a pathname
    (if (pathnamep p)
	(cond
	 (#:system:unixp (#:unix:true-pathname p))
	 ((eq (system) 'vaxvms) (#:vaxvms:true-pathname  p))
	 (t (to-system 'true-pathname p)))
      (error 'true-pathname ERRBPA p)))


(de #:unix:true-pathname (p)
    ;; the convention assumed here is that environnement variables
    ;; have been inserted somewhere in the pathname... as the first
    ;; element of the directory list (which will start with :current,)
    ;; or instead of the name of the file... we recognize it because
    ;; it starts with a "$" sign... so we use (getenv) to see if by
    ;; chance...... 
    (let ((new-p (new 'pathname))
          (new-s ()))
      (if
       (and (eq (car (:directory p)) ':current)
             (stringp (cadr (:directory p)))
	     (eq (sref (cadr (:directory p)) 0) #/$)
             (setq new-s (getenv (substring  (cadr (:directory p))
					     1)))
             (setq new-s (string new-s)))
	(:directory new-p 
                (cons 
                  (ifn (eq (sref new-s 0)#//)
                        new-s
                       (substring new-s 1))
                   (caddr (:directory p))))
	(:directory new-p (:directory p)))
      (if (and (stringp (:name p))
	       (eq (sref (:name p) 0 ) #/$)
               (setq new-s (string (getenv (substring (:name p) 1)))))
	  (:name new-p new-s)
	  (:name new-p (:name p)))
      (:type new-p (:type p))
      (:version new-p (:version p))
     (#:unix:pathname (#:unix:namestring new-p))))
       


;;; the kernel for  VMS... but it doesn't work yet  since it requires
;;; the help of an internal operating system routine 


(de #:vaxvms:true-pathname (s)
    ;; On VAX/VMS the normal way is to use logical names...
    ;; so what we do is to build the external string, and call the
    ;; system service.. then we build the new pathname
    (pathname (#:vaxvms:trlnm (#:vaxvms:namestring p))))

;;;a pseudo
(de #:vaxvms:trlnm(s) s)       ;the compiler won't complain


;;; now, much greater... 
;;; a get/set working directory, the portable way

(de current-directory p
     ;; P is a pathname, a string, or ()
	(cond
	 (#:system:unixp (#:unix:current-directory (car p)))
	 ((eq (system) 'vaxvms) (#:vaxvms:current-directory(car  p)))
	 (t (to-system 'current-directory (car  p)))))


;; the unix-way


(de #:unix:current-directory p
    (cond ((not (car p))
	   (let ((the←string (makestring 100 #/ ))
                 (ret-length ()))
	     (setq ret-length (←llgetwd the←string 100))
	     (substring the←string 0 ret-length)))
	  ((pathnamep (car p))
	   (let ((the←directory 
		  (or (stringp p)
		      (directory-namestring (car p)))))
	     (←llglobb the←directory the←directory 0)))
	  (t (error 'current-directory ERRBPA (car p)))))

#+#:system:unixp
(progn
(defextern  ←llgetwd(string fix) fix )
(defextern ←llglobb (string string fix) fix)
)


;;; And Now, ladies and gentlemen.... The wild carding process
;;; very special ....
;;; the following code uses a pathname or an external string as
;;; argument and returns all wildcarding possibilities... it is the
;;; user's responsability to do what it needs with it...

(de expand-pathname (p)
    ;;p is a pathname or a string which follows the full convention of
    ;;the host system
    (cond
     (#:system:unixp (#:unix:wild  p))
     ((eq (system) 'vaxvms) (#:vaxvms:wild  p))
     (t (to-system 'wild (car  p)))))

(defvar #:unix:wildbuffer (makestring 1024 #/ ))

(de #:unix:wild (p)
    (let ((the←string #:unix:wildbuffer)
	  (the←pattern (or (stringp p) (namestring p)))
	  (the←result ())		; list of the returned pathnames
          (the←slen ())
	  (i ())
          (j ()))			; working indexes
      (setq the←slen (slen the←string))
      (setq i (←llglobb the←pattern the←string the←slen))

      ;; strange return-codes from lelisp.c
      (when (< i 0)
         (setq i (←llglobb the←pattern the←string the←slen))
         (if (< i 0)
            (error 'errios '#:unix:wild i)))
      
      ;; buffer limits exceeded
      (when (lt (differ the←slen i) 6)
         (←llglobb "" "" -1)
         (error 'errstl '#:unix:wild the←pattern))

      ;;in i, we have now the effective size of the buffer
      ;;the←string : the returned buffer
      (setq the←string (substring the←string 0 i))

      (chrset (sub1 (slen the←string)) the←string #/ )
      (while (neq i 0)
	(setq j (chrpos 32 the←string))
	(newl the←result
	      (#:unix:pathname (substring the←string 0 j)))
	(setq i (slen (setq the←string (substring the←string (add1 j))))))
      (nreverse the←result)))


;;stubs for VMS.. the compiler won't complain
 (de #:vaxvms:current-directory p ()"")
 (de #:vaxvms:wild (p) ())

;;; this function coerces an external string, and when required,
;;; checks the syntaxe of the pathname

(de coerce-namestring (file-name)
    (if (pathnamep file-name)
	(progn
	  (when *portable-pathname* (portable-pathname-p file-name))
	  (namestring file-name))
      file-name))