Каковы соглашения с подстановочными знаками путей SBCL в macOS, Linux, FreeBSD? - PullRequest
0 голосов
/ 22 января 2019

Испытывая Lisp сегодня на моем Mac, я обнаружил, что следующее немного дезориентирует:

$ sbcl
This is SBCL 1.4.14, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.

* (directory "*")
NIL

* (directory "*.*")
(#P"/private/tmp/sbcl/quicklisp.lisp" #P"/private/tmp/sbcl/test1.lisp"
 #P"/private/tmp/sbcl/test2.lisp")

В macOS, Linux, FreeBSD, возможно, в большинстве других UNIX-подобных типов, * представляет все файлы. Я только когда-либо видел *.*, используемый в DOS и Windows.

В соответствии с описанием directory подстановочные знаки зависят от реализации. Итак, что же такое соглашение, используемое SBCL в вышеуказанных операционных системах? Как мне это узнать? Руководство SBCL не описывает этого. Может ли быть иначе даже между тремя ОС выше?

Ответы [ 2 ]

0 голосов
/ 28 января 2019

Следующее работает, и я думаю, что оно должно работать в большинстве реализаций (я пробовал это на LW на MacOS, SBCL на Linux и Clojure на MacOS).

(defun directory-pathname (p)
  ;; Everything but the file part: this should be called
  ;; non-file-pathname or something
  (make-pathname :name nil :type nil :version nil
                 :defaults (pathname p)))

(defconstant +wild-file+
  ;; a completely wildcarded filename with no other components
  (make-pathname :name ':wild
                 :type ':wild
                 :version ':wild))

(defun wild-directory (d)
  ;; Take the directory parts of D and return a pathname which matches
  ;; all files in tat directory.
  ;;
  ;; Actually we could just use D for the defaults since it's only
  ;; used for defaults and that's less consy, but never mind
  (merge-pathnames +wild-file+ (directory-pathname d)))

Затем, например, (directory (wild-directory "/tmp/")) вернет все в каталоге /tmp/, а (directory (wild-directory (user-homedir-pathname))) вернет все в вашем домашнем каталоге.

Однако обратите внимание, что (это явно очень зависит от реализации, но похоже, что все реализации, которые я использую, согласны с этим, и я согласен с их интерпретацией): (directory (wild-directory "/tmp")) вернет все в / потому что "/tmp" в качестве пути означает «файл с именем tmp в каталоге с именем /». Как я уже сказал, я думаю, что это разумная интерпретация: имена путей, которые ссылаются на каталоги, заканчиваются на /.

Также обратите внимание, что +wild-file+ действительно дикий: он не обрабатывает файлы, чьи имена начинаются с . каким-либо особым образом. Я думаю, что существует довольно очевидная двусмысленность в том, как следует анализировать имена файлов, такие как /foo/bar/.x, хотя все три реализации, которые я пробовал, принимают правильную интерпретацию: имя ".x" и тип nil (/foo/bar/.x.y, кажется, разбирается с типом "y", что я думаю, также разумно).

В любом случае, когда вам нужно выполнить какую-либо серьезную манипуляцию с именем пути, уловка состоит в том, чтобы определить набор функций и констант-оболочек, которые вы затем используете, и за которыми вы можете скрыть зависимость от реализации (в этом случае зависимость от реализации как получить все файлы в каталоге, все остальное, похоже, является общим для реализаций).

Я подозреваю, что такой уровень абстракции существует, но, к сожалению, я не знаю, что это такое.


После написания этого я попробовал CLISP, и он делает что-то интересное: похоже, что directory не возвращает имена подкаталогов, только имена файлов. Я думаю, что это вполне разумная реализация, но она потребует еще большей абстракции.

0 голосов
/ 24 января 2019

Источники SBCL имеют этот комментарий :

;;; FIXME: the below shouldn't really be here, but in documentation
;;; (chapter 19 makes a lot of requirements for documenting
;;; implementation-dependent decisions), but anyway it's probably not
;;; what we currently do.
;;;
;;; Unix namestrings have the following format:
;;;
;;; namestring := [ directory ] [ file [ type [ version ]]]
;;; directory := [ "/" ] { file "/" }*
;;; file := [^/]*
;;; type := "." [^/.]*
;;; version := "." ([0-9]+ | "*")
;;;
;;; Note: this grammar is ambiguous. The string foo.bar.5 can be
;;; parsed as either just the file specified or as specifying the
;;; file, type, and version. Therefore, we use the following rules
;;; when confronted with an ambiguous file.type.version string:
;;;
;;; - If the first character is a dot, it's part of the file. It is not
;;; considered a dot in the following rules.
;;;
;;; - Otherwise, the last dot separates the file and the type.
;;;
;;; Wildcard characters:
;;;
;;; If the directory, file, type components contain any of the
;;; following characters, it is considered part of a wildcard pattern
;;; and has the following meaning.
;;;
;;; ? - matches any one character
;;; * - matches any zero or more characters.
;;; [abc] - matches any of a, b, or c.
;;; {str1,str2,...,strn} - matches any of str1, str2, ..., or strn.
;;;   (FIXME: no it doesn't)
;;;
;;; Any of these special characters can be preceded by an escape
;;; character to cause it to be treated as a regular character.

В нем говорится "но в любом случае это, вероятно, не то, что мы делаем в настоящее время", но я неконечно, если это означает, что этот комментарий может быть неточным для текущих версий или что-то еще.Я предполагаю, что, по крайней мере, подстановочный знак является достаточно правильным.

Важной частью здесь является то, что компоненты каталога, файла и типа рассматриваются отдельно, поэтому у вас должен быть отдельный подстановочный знак для имени файла ирасширение (также называемое компонентом типа) с точкой для их разделения.

Комментарий называет эти "строки имен Unix", но я предполагаю, что это применимо ко всем платформам.

...