Newer
Older
(t (format t "Couldn't stat ~A -- ~A.~%"
tail
(push (if (= (logand mode unix:s-ifmt) unix:s-ifdir)
(pathname (concatenate 'string namestring "/"))
file)
result)))))
(nreverse result)))
(defun decode-universal-time-for-files (time current-year)
(multiple-value-bind (sec min hour day month year)
(decode-universal-time (+ time unix-to-universal-time))
(declare (ignore sec))
(format nil "~A ~2,' D ~:[ ~D~;~*~2,'0D:~2,'0D~]"
(svref '#("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug"
"Sep" "Oct" "Nov" "Dec")
(1- month))
day (= current-year year) year hour min)))
(defun print-directory-formatted (pathname all return-list)
(let ((width (or (line-length *standard-output*) 80))
(names ())
(cnt 0)
(max-len 0)
(result (directory pathname :all all :truenamep nil)))
(declare (list names) (fixnum max-len cnt))
;;
;; Get the data.
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
(dolist (file result)
(let* ((name (unix-namestring file))
(length (length name))
(end (if (and (plusp length)
(char= (schar name (1- length)) #\/))
(1- length)
length))
(slash-name (subseq name
(1+ (or (position #\/ name
:from-end t
:end end
:test #'char=)
-1))))
(len (length slash-name)))
(declare (simple-string slash-name)
(fixnum len))
(if (> len max-len) (setq max-len len))
(incf cnt)
(push slash-name names)))
(setq names (nreverse names))
;;
;; Do the output.
(let* ((col-width (1+ max-len))
(cols (max (truncate width col-width) 1))
(lines (ceiling cnt cols)))
(declare (fixnum cols lines))
(format t "Directory of ~A :~%" (namestring pathname))
(dotimes (i lines)
(declare (fixnum i))
(dotimes (j cols)
(declare (fixnum j))
(let ((name (nth (+ i (the fixnum (* j lines))) names)))
(when name
(write-string name)
(unless (eql j (1- cols))
(dotimes (i (- col-width (length (the simple-string name))))
(write-char #\space))))))
(terpri)))
(when return-list
result)))
;;;; File completion.
(defun complete-file (pathname &key (defaults *default-pathname-defaults*)
ignore-types)
(let ((files (directory (complete-file-directory-arg pathname defaults)
:check-for-subdirs nil
:truenamep nil)))
(cond ((null files)
(values nil nil))
((null (cdr files))
(values (merge-pathnames (file-namestring (car files))
pathname)
t))
(t
(let ((good-files
(delete-if #'(lambda (pathname)
(and (simple-string-p
(pathname-type pathname))
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
(member (pathname-type pathname)
ignore-types
:test #'string=)))
files)))
(cond ((null good-files))
((null (cdr good-files))
(return-from complete-file
(values (merge-pathnames (file-namestring
(car good-files))
pathname)
t)))
(t
(setf files good-files)))
(let ((common (file-namestring (car files))))
(dolist (file (cdr files))
(let ((name (file-namestring file)))
(dotimes (i (min (length common) (length name))
(when (< (length name) (length common))
(setf common name)))
(unless (char= (schar common i) (schar name i))
(setf common (subseq common 0 i))
(return)))))
(values (merge-pathnames common pathname)
nil)))))))
;;; COMPLETE-FILE-DIRECTORY-ARG -- Internal.
;;;
(defun complete-file-directory-arg (pathname defaults)
(let* ((pathname (merge-pathnames pathname (directory-namestring defaults)))
(type (pathname-type pathname)))
(flet ((append-multi-char-wild (thing)
(etypecase thing
(null :wild)
(pattern
(make-pattern (append (pattern-pieces thing)
(list :multi-char-wild))))
(simple-string
(make-pattern (list thing :multi-char-wild))))))
(if (or (null type) (eq type :unspecific))
;; There is no type.
(make-pathname :defaults pathname
:name (append-multi-char-wild (pathname-name pathname))
:type :wild)
;; There already is a type, so just extend it.
(make-pathname :defaults pathname
:name (pathname-name pathname)
:type (append-multi-char-wild (pathname-type pathname)))))))
;;; Ambiguous-Files -- Public
(defun ambiguous-files (pathname
&optional (defaults *default-pathname-defaults*))
"Return a list of all files which are possible completions of Pathname.
We look in the directory specified by Defaults as well as looking down
the search list."
(directory (complete-file-directory-arg pathname defaults)
:truenamep nil
:check-for-subdirs nil))
;;; File-writable -- exported from extensions.
;;;
;;; Determines whether the single argument (which should be a pathname)
(defun file-writable (name)
"File-writable accepts a pathname and returns T if the current
process can write it, and NIL otherwise."
(let ((name (unix-namestring name nil)))
(cond ((null name)
nil)
((unix:unix-file-kind name)
(values (unix:unix-access name unix:w_ok)))
(t
(values
0
(or (position #\/ name :from-end t)
0))
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
;;; Pathname-Order -- Internal
;;;
;;; Predicate to order pathnames by. Goes by name.
;;;
(defun pathname-order (x y)
(let ((xn (%pathname-name x))
(yn (%pathname-name y)))
(if (and xn yn)
(let ((res (string-lessp xn yn)))
(cond ((not res) nil)
((= res (length (the simple-string xn))) t)
((= res (length (the simple-string yn))) nil)
(t t)))
xn)))
;;; Default-Directory -- Public
;;;
(defun default-directory ()
"Returns the pathname for the default directory. This is the place where
a file will be written if no directory is specified. This may be changed
with setf."
(multiple-value-bind (gr dir-or-error)
(let ((*ignore-wildcards* t))
(values
(parse-namestring (concatenate 'simple-string dir-or-error "/")
*unix-host*)))
;;; %Set-Default-Directory -- Internal
;;;
(defun %set-default-directory (new-val)
(let ((namestring (unix-namestring new-val t)))
(unless namestring
(error 'simple-file-error
:format-control "~S doesn't exist."
:format-arguments (list new-val)))
(multiple-value-bind (gr error)
(if gr
(setf (search-list "default:") (default-directory))
;;;
(defsetf default-directory %set-default-directory)
(defun filesys-init ()
(setf *default-pathname-defaults*
(%make-pathname *unix-host* nil nil nil nil :newest))
(setf (search-list "default:") (default-directory))
nil)
;;; Ensure-Directories-Exist -- Public
;;;
(defun ensure-directories-exist (pathspec &key verbose (mode #o777))
"Tests whether the directories containing the specified file
actually exist, and attempts to create them if they do not.
Portable programs should avoid using the :MODE keyword argument."
(let* ((pathname (pathname pathspec))
(pathname (if (logical-pathname-p pathname)
(translate-logical-pathname pathname)
pathname))
(created-p nil))
(when (wild-pathname-p pathname)
(error 'simple-file-error
:format-control "Bad place for a wild pathname."
:pathname pathspec))
(enumerate-search-list (pathname pathname)
(let ((dir (pathname-directory pathname)))
(loop for i from 1 upto (length dir)
do (let ((newpath (make-pathname
:host (pathname-host pathname)
:device (pathname-device pathname)
:directory (subseq dir 0 i))))
(unless (probe-file newpath)
(let ((namestring (namestring newpath)))
(when verbose
(format *standard-output* "~&Creating directory: ~A~%"
namestring))
(unix:unix-mkdir namestring mode)
(unless (probe-file namestring)
(error 'simple-file-error
:pathname pathspec
:format-control "Can't create directory ~A."
:format-arguments (list namestring)))
(setf created-p t)))))
;; Only the first path in a search-list is considered.
(return (values pathname created-p))))))