A pathname in the file system of Common-Lisp consists of six elements: host, device, directory, name, type and version. Pathnames are read and printed using the #P
reader macro followed by the namestring. A namestring is a string which represents a pathname. The syntax of namestrings for logical pathnames is well explained in the ANSI [see ANSI] and it can be roughly summarized as follows:
[hostname:][;][directory-item;]0 or more[name][.type[.version]] hostname = word directory-item = wildcard-word type, name = wildcard-word without dots
Here, wildcard-word is a sequence of any character excluding #\Null
and dots. word is like a wildcard-word but asterisks are excluded.
The way ECL parses a namestring is by first looking for the hostname component in the previous template. If it is found and it corresponds to a previously defined logical hostname, it assumes that the namestring corresponds to a logical pathname. If hostname is not found or it is not a logical hostname, then ECL tries the physical pathname syntax
[device:][[//hostname]/][directory-item/]0 or more[name][.type] device, hostname = word directory-item = wildcard-word type = wildcard-word without dots name = [.]wildcard-word
If this syntax also fails, then the namestring is not a valid pathname string and a parse-error
will be signaled.
It is important to remark that in ECL, all physical namestrings result into pathnames with a version equal to :newest
. Pathnames which are not logical and have any other version (i. e. nil
or a number), cannot be printed readably, but can produce a valid namestring which results of ignoring the version.
Finally, an important rule applies to physical namestrings: if a namestring contains one or more periods ‘.’, the last period separates the namestring into the file name and the filetype. However, a namestring with a single leading period results in a name with a period in it. This is for compatibility with Unix filenames such as .bashrc
, where the leading period indicates that the file is hidden.
The previous rule has in important consequence, because it means that if you want to create a pathname without a name, you have to do it explicitely. In other words, ".*"
is equivalent to (make-pathname :name ".*" :type nil)
, while (make-pathname :name nil :type :wild)
creates a pathname whose type is a wildcard.
The following table illustrates how the physical pathnames work with practical examples.
Namestring | Name | Type | Directory | Device |
---|---|---|---|---|
"foo.lsp" | "foo" | "lsp" | nil | nil |
".bashrc" | ".bashrc" | nil | nil | nil |
".ecl.lsp" | ".ecl" | "lsp" | nil | nil |
"foo.*" | "foo" | :wild | nil | nil |
"*.*" | :wild | :wild | nil | nil |
"ecl/build/bare.lsp" | "bare" | "lsp" | (:relative "ecl" "build") | nil |
"ecl/build/" | nil | nil | (:relative "ecl" "build") | nil |
"../../ecl/build/" | nil | nil | (:relative :up :up "ecl" "build") | nil |
"/etc/" | nil | nil | (:absolute "etc") | nil |
"C:/etc/" | nil | nil | (:absolute "etc") | "C" |
".*" | ".*" | nil | nil | nil |
#.(make-pathname :type "*") | nil | :wild | nil | nil |
ECL accepts four kind of wildcards in pathnames.
:wild
value. See for instance "*.*
", "/home/*/.bashrc
", etc
/home/**/
" is parsed as the :wild-inferiors
, and matches any number of directories, even nested ones, such as: /home/
, /home/jlr
, /home/jlr/lib
, etc.
log*.txt
" matches any number of characters: log.txt
, log_back.txt
, etc.
log?.txt
" matches a single character: log1.txt
, log2.txt
...
The matching rules in Common Lisp and ECL are simple but have some unintuitive consequences when compared to Unix/DOS rules. The most important one is that directories must always end with a trailing slash /
, as in #p"/my/home/directory/"
. Second to that, nil
values can only be matched by nil
and :wild
. Hence, "*
" can only match files without file type. For some examples see Dictionary.
Common Lisp and C equivalence
Lisp symbol | C function |
---|---|
directory-namestring | cl_object cl_directory_namestring(cl_object pathname) |
enough-namestring | cl_object cl_enough_namestring(cl_narg narg, cl_object pathname, ...) |
file-namestring | cl_object cl_file_namestring(cl_object pathname) |
host-namestring | cl_object cl_host_namestring(cl_object pathname) |
load-logical-pathname-translations | cl_object cl_load_logical_pathname_translations(cl_object host) |
logical-pathname-translations | cl_object cl_logical_pathname_translations(cl_object host) |
logical-pathname | cl_object cl_logical_pathname(cl_object pathspec) |
make-pathname | cl_object cl_make_pathname(cl_narg narg, ...) |
merge-pathnames | cl_object cl_merge_pathnames(cl_narg narg, cl_object pathname,...) |
namestring | cl_object cl_namestring(cl_object pathname) |
parse-namestring | cl_object cl_parse_namestring(cl_narg narg, cl_object thing, ...) |
pathname | cl_object cl_pathname(cl_object pathspec) |
pathname-device | cl_object cl_pathname_device(cl_narg narg, cl_object pathname, ...) |
pathname-directory | cl_object cl_pathname_directory(cl_narg narg, cl_object pathname, ...) |
pathname-host | cl_object cl_pathname_host(cl_narg narg, cl_object pathname, ...) |
pathname-match-p | cl_object cl_pathname_match_p(cl_object pathname, cl_object wildcard) |
pathname-name | cl_object cl_pathname_name(cl_narg narg, cl_object pathname, ...) |
pathname-type | cl_object cl_pathname_type(cl_narg narg, cl_object pathname, ...) |
pathname-version | cl_object cl_pathname_version(cl_object pathname) |
pathnamep | cl_object cl_pathnamep(cl_object object) |
translate-logical-pathname | cl_object cl_translate_logical_pathname(cl_narg narg, cl_object pathname, ...) |
translate-pathname | cl_object cl_translate_pathname(cl_narg narg, cl_object source, cl_object from_wildcard, cl_object to_wildcard, ...) |
wild-pathname-p | cl_object cl_wild_pathname_p(cl_narg narg, cl_object pathname, ...) |