.c      Thursday  Oct 21,1982  20:19  NM+4D.14H.32M.27S.  -*- Bolio -*-

.chapter "File System Interface"
.setq file-system-chapter-section-page section-page


.section "Pathnames"

The lan{nil} scheme of representing pathnames is, for the most part,
a simpleminded version of that present in Lisp Machine Lisp.

In lan{nil}, the names for files are not represented as just strings
or lists of components, but as objects of type kwd_i{pathname}.  A
pathname has five basic components described below.
.table 3 250 250 0 0 0
.item host
This is an object which describes the filesystem the pathname refers
to.  All pathnames have such a component, filled in;  the host is
necessary to complete the parsing of a pathname.  Of course, in a
normal lan{nil}, there is only one such object because lan{nil}
currently only talks to the local disk filesystem.
.item device
This is a string naming the device.
.item directory
A string naming the directory, or, if the directory is structured, a
list of strings.
.item name
The name of the file.  (In some filesystems, there could be multiple
names, so this could be a list.)
.item type
The "type" of the file.  Under lan{vms} this does not always
correspond directly to the extension, but is often a longer name which
is mapped (from a database) into the extension to be used.  For
instance, the type 7"LISP"* (a string) maps into the extension
7LSP*, and 7"PATCH-SYSTEM-DEFINITION"* maps into 7PSD*.
.item version
This designates the file version or generation number, which is
represented as an integer.
.end_table
In addition to the canonical quantities above which may appear as
various pathname components, there are some special symbols which may
appear in parts of pathnames in various ways:
.table 3 250 250 0 0 0
.item nil
3nil* as a pathname component means that the component was not
specified.  Pathname merging (see below) will supply this component
from another pathname.
.item :wild
The keyword 3:wild* may occur as either a pathname component, or
as an element of a structured pathname component (in lan{vms}, only
in a directory).  It represents a wildcard, as might be represented by
a "*" in the printed (host) representation.  For instance, the
pathname for 7sys$login:foo.** has a 3type* component of
3:wild*, and 7nil$disk:[nil.patch.*]*.psd* a 3directory*
component of 3("NIL" "PATCH" :WILD)* and a 3name* component of
3:wild*.
.item :implied
This is somewhat of a kludge.  What it means is that while the
component is not explicitly specified, it is implied by the logical
name translation of the device.  For instance, the 7SYS$LOGIN*
logical name usually translates into both a device and a directory
component;  thus, the 3directory* component of the pathname
generated from (say) 7SYS$LOGIN:LOGIN.COM* will be 3:implied*.
This keyword can occur in the directory, name, type, and/or version
components of a pathname, although typically it only does so in the
directory.
.item :unspecific
This is not used for anything yet.  Its purpose is to say that, while
the component is not "missing", it is not specified.  A pathname with
components of 3:unspecific* does not refer to a specific file, but
rather talks about the class of files which would match it;  in
particular, in order to associate information with a class of
pathnames.  (While 3:wild* might be considered a generator of
pathnames, 3:unspecific* implies that the pathname is generic.)
Something like that.
.item :relative
This is currently only used for describing lan{vms} term_i{rooted
directories}.  Usually it is only encountered internally in parsing of
pathnames which contain logical names translating to such rooted
directories.  It only occurs (now) as a dotted end on a structured
directory.  For instance, the directory component of
7nil$disk:[nil.]foo.bar* is 3("NIL" . :relative)*.
.item :elipsis
This might be a braino which should just be 3:wild*.  It only
occurs as a dotted end in structured directories.  The directory
component of 7nil$disk:[nil...]*.lsp;" is 3("NIL" .
:elipsis)*, and of 7nil$disk:[*...]*.mdl;* is 3(:wild .
:elipsis).
.item :newest
This can only appear as the 3version* component of a pathname.  It
means the highest version.  Note that while a version of 3nil* in
a pathname almost always comes out to be equivalent, it 2could*
get a version of something else (like 37*) substituted in by
pathname merging--either explicitly by user code or implicitly from
some hidden defaults by lan{nil}.
.end_table

One convention currently used is that there 2is* a local
filesystem.  This host is, by default, named lan{local}.  It is also
(gratuitously) given names which lan{nil} derives from the
environment specific to the machine:  the preferred one is that used
by Chaosnet software, gotten from the logical name HOST$LOCALNAME, and
'cindex HOST$LOCALNAME logical name
'cindex logical name, HOST$LOCALNAME
'cindex SYS$NODE logical name
'cindex logical name, SYS$NODE
next in line that used by lan{vms} and lan{decnet} software,
gotten from the logical name SYS$NODE (with preceding underscores and
trailing colons and spaces stripped off).

.subsection "Pathname Functions"

.defun pathname thing
2thing* is coerced into a pathname.

If it is a pathname, it is returned.

If it is a list, then it is assumed to be a lan{maclisp} namelist;
interpretation of this, and lan{maclisp} compatible pathname
handling, is discussed in (maclisp-pathname-section-page).

If it is a string (or symbol), then the text is examined for a prefix
or suffix component, followed by a ":", which is a host string;  if
one is found, then that is the host used, otherwise a host is
defaulted (the handling of this is pretty spastic right now, but
hardly matters as there is only one host).  The string is then parsed
in the manner specific to that host, and the resultant pathname
returned.
.end_defun

.defun pathname-host pathname
.defun1 pathname-device pathname
.defun1 pathname-directory pathname
.defun1 pathname-name pathname
.defun1 pathname-type pathname
.defun1 pathname-version pathname
These return the components of 2pathname*, which is coerced to a
pathname with the fun{pathname} function.
.end_defun


.defun namestring pathname
2pathname* is coerced to a pathname with the fun{pathname}
function, and its "standard printed representation" returned, as a
string.
.end_defun

.defun user-homedir-pathname &optional host
Returns the user's home directory, as a pathname:  the kwd{name},
kwd{type}, and kwd{version} components will be unspecified.

The home directory is where files specific to the user are looked for
(or defaulted to).  See, for instance, fun{init-file-pathname},
(init-file-pathname-fun).

Under lan{vms}, this is obtained by translating the logical name
'cindex SYS$LOGIN logical name
'cindex logical name, SYS$LOGIN
7SYS$LOGIN*.
.end_defun

.defun user-workingdir-pathname &optional host
Returns the user's working directory, as a pathname:  the kwd{name},
kwd{type}, and kwd{version} components will be unspecified.

For a local lan{vms} filesystem, this is the lan{rms} default
device/directory string, which is what is modified by 7set
default* in lan{dcl}.  If for some reason the string returned by
lan{rms} does not have a device specified, 7SYS$DISK* will be
supplied for the device component.
.end_defun

.defun user-scratchdir-pathname &optional host
Returns, as a pathname, the directory of the directory which should be
used by programs for writing "scratch" files.

The local-vms host uses the value of the logical name
'cindex SYS$SCRATCH logical name
'cindex logical name, SYS$SCRATCH
'cindex SYS$DISK logical name
'cindex logical name, SYS$DISK
7SYS$SCRATCH* if that exists, otherwise the user's home directory.
If for some reason the device field is absent, 7SYS$DISK* is
supplied.
.end_defun

.defun init-file-pathname program-name &optional host
This returns the pathname of the user's init file for
2program-name* on 2host*.  2program-name* should be a
string.

For lan{nil} under lan{vms}, the init file is on the user's home
directory, and has name lan{nil} and extension lan{ini}.  This
same convention is used in general by this function;  for an arbitrary
program name, the init file is named, essentially,
.lisp
SYS$LOGIN:2program-name*.INI
.end_lisp
In the lan{nil} programming environment, this is more for the use of
lan{lisp} subsystems than a general facility (which could do things
like determine the init file for logging into the vax).  For example,
if you had a system lan{lsb} which people loaded into their
lan{nil}, or which was dumped out in a lan{nil}, it might load an
lan{lsb} init file.  Note that there is a problem here if
2program-name* is not valid as a pathname kwd{name} component.
.end_defun

.subsection "Merging and Defaulting"

Merging and defaulting are the actions used to fill in components
missing from a pathname specification, usually when the pathname is
about to be used to reference something in the filesystem.  For the
most part, this involves supplying the components missing in one
pathname from another.  The algorithm used is slightly more
complicated, and is described under fun{merge-pathname-defaults},
below.

In lan{nil}, the pathname defaults for a specific application are
maintained in a term_i{pathname defaults} object (it will probably
be of type kwd{fs:pathname-defaults}).  This enables modular
handling of supplying of defaults for multiple hosts, pathname
"stickiness" for sets of commands, etc.  The defaults are often used
to supply the host with respect to which some operation must be
performed, such as pathname parsing.

.defun merge-pathname-defaults pathname &optional defaults default-type default-version
This is the main merger.  2pathname* may be anything coercible to
a pathname.  2defaults* may be a pathname defaults object, a
pathname, or a string or symbol (which will be coerced to a pathname
first).  2default-type* and 2default-version* may be whatever is
allowable for types and versions.

If it is necessary, 2pathname* will be parsed with respect to a
host determined from 2defaults*.  If the directory field of it is
missing, then that will be supplied by 2defaults*.  There is some
question as to what should happen if the device field of
2pathname* is missing:  currently, it is simply filled in from
2defaults*.  In the Lisp Machine implementation of this function,
it is supplied as the default device for the host (perhaps
inconsistently, for instance only when parsed from a string?);
probably what should happen is that whether the device comes from
2defaults* or not is determined by the host, so that it would if
the devices were really structured (with directories in them etc.),
and would not otherwise (which in Lisp Machine Lisp appears to be
mainly for the sake of the ITS operating system).

If 2pathname* has a name supplied, then if the type and version of
the resulting pathname are defaulted from 2default-type* and
2default-version*, as necessary.  Otherwise, the name, type, and
version are defaulted from 2defaults*.  Thus:
.lisp
(merge-pathname-defaults
   "[nil.vas]foo" "sys$disk:[gsb]zz.lsp;3" "vasl")
  => #<local-vms-pathname "node:sys$disk:[nil.vas]foo.vas">
(merge-pathname-defaults
   "[nil.vas]" "sys$disk:[gsb]zz.lsp;3" "vasl")
  => #<local-vms-pathname "node:sys$disk:[nil.vas]zz.lsp;3">
(merge-pathname-defaults
   "[nil.vas]=.inp" "sys$disk:[gsb]zz.lsp;3" "lisp")
  => #<local-vms-pathname "node:sys$disk:[nil.vas]zz.inp;3">
.end_lisp
In the above, it is worth noting that "=" as a pathname component is
used as a placeholder for an unspecified component, and that a file
type of 3lisp* is mapped (by the lan{vms} pathname code) into an
extension of 3lsp*, and 3vasl* to 3vas*.  The specifics of
the syntax and file-type/extension mapping are described elsewhere.
.end_defun


Here are some of the defaults in use in lan{nil}.

.defvar *load-pathname-defaults*
This is used to provide pathname defaults for fun{load},
fun{compile-file}, and any similar functions.  It is initialized to
the user's working directory with name 7FOO* and type 7LISP*
(see fun{user-workingdir-pathname},
(user-workingdir-pathname-fun)).
.end_defvar

.defvar *default-pathname-defaults*
This provides super-defaults for anything that needs them, such as
fun{open}, fun{with-open-file}, and parsing a pathname string out
of context.  It is initialized to the user's working directory with
name 7FOO* and type 7LISP* (see
fun{user-workingdir-pathname}, (user-workingdir-pathname-fun)).
.end_defvar

.defvar *scratch-pathname-defaults*
This is used by things which must write out "temporary" files.
Things which use this should not modify it;  it should be left to the
user to set default pathnames for hosts (primarily for the sake of the
device and directory) to say where such files should be written. See
fun{user-scratchdir-pathname}, (user-scratchdir-pathname-fun).

For example, the current lan{nil} fun{compile} function creates a
file named 3aaafoo.vas*, and supplies the device and directory
from var{*scratch-pathname-defaults*}.
.end_defvar



.section "Opening Files"

.defun open frob &rest gubble
In lan{nil}, fun{open} does more than just open files.  That,
however, is what most users do with it most of the time, so it is
described here.

First, 2gubble* is put into a canonicalized form.  Essentially,
fun{open} is considered to take alternating keyword/value arguments.
However, for lan{maclisp} compatibility, if fun{open} is given
exactly two arguments, the second is interpreted as either a single
keyword, or a list of single keywords, which are mapped specially into
the standard fun{open} keyword arguments.  Thus, in lan{nil},
.lisp
(open 2pathname* 'out)
.end_lisp
opens 2pathname* as a standard buffered ascii output file, and 
.lisp
(open 2pathname*)
.end_lisp
opens 2pathname* as an ordinary buffered ascii input file.

fun{open} attempts to determine the way in which to actually perform
the open by looking at the options.  I am being very vague about this
because it is going to change somewhat, but hopefully will remain
upwards compatible.  If there is a kwd{:type} keyword, then the
argument to that is
used to tell fun{open} what type of open is being performed.  The
interesting ones right now are
.table 3 250 250
.item :dsk
which says that 2frob* should be interpreted as a pathname, and
the fun{open} will refer to a file in some filesystem.  The
specifics of this for lan{vms} are discussed later in this section
((vms-open-specifics)).
.item :tty
which says that 2frob* is the name of a terminal (it may be
(false), meaning use the default terminal name 3TT*), or a
string with or without a 3:* terminating it, or a pathname in
which the device is used), and the open should behave accordingly.
This tty may actually be quite useless, and you probably want instead
.item :display-tty
which is like kwd{:tty} but sets things up so that
fun_i{cursorpos} will work on it.  This is discussed more thoroughly
in (display-tty-section-page).
.end_table

If no kwd{:type} is specified and 2frob* is a stream, it is sent
the msg_i{:open} message with
arguments 2gubble*.  The normal use of this is to re-open a stream
which has been closed, and in this case no arguments are normally
needed.  Not all streams necessarily support this, but all currently
defined lan{nil} streams which might be returned by fun{open} and
to which fun{close} is meaningful, do.  Many streams which support
this support the msg_i{:set-pathname} message, which is the
primitive form of the lan{maclisp} fun_i{cnamef} function;  this
allows changing the pathname which will be opened when a closed stream
is reopened.
.end_defun

.defspec with-open-file (var frob &rest gubble) body...
This binds 2var* to the result of opening 2frob* with options
2gubble*, and executes 2body* in that environment.  When the
2body* is exited, the file is closed.  (You cannot fool
fun{with-open-file} by fun{setq}ing 2var*.)  If the form is
exited abnormally, by an error, quit, or fun{*throw}, the file is
closed in kwd{:abort} mode;  for a freshly written output file, this
means it is deleted.

The behaviour of fun{with-open-file} with respect to treatment of
2frob* and 2gubble*, and to errors in opening, is identical to
fun{open} otherwise.

fun{with-open-file} should be used wherever that scoping is
reasonable, so that stray open files are not left around by buggy
programs.  There is also potential for it to be somewhat more storage
efficient due to use of resources, since the extent of the created
stream is known to be dynamic (it is not valid to pass it back outside
of the fun{with-open-file} form).  This is not done yet, but will
be someday.
.end_defspec

.defun fs:close-all-files
In case you ido* mess up and lose track of some files, this will
close all open files (which have been really opened as streams, not
just kludgey temporary opens).  Every known host object is supposed to
keep track of all streams which it has open, in such a way as to be
secure against timing screws, so that this may at least be done.

Doing 3(exhibit fs:*host-instances*)* should give one a
handle on the open files, as the host instances should point to the
files they have open.  var_i{fs:*host-instances} is the list of all
known hosts, which is used to (among other things) drive host-name
lookup.
.end_defun

.setq vms-open-specifics page
lan{Nil} currently employs only two modes of file opening.  These
correspond to kwd{:ascii} and kwd{:byte} modes.

kwd{:ascii} will cause the file to be written as variable-length
records, with record-attribute of carriage-return.  The existing disk
I/O code does not have the intelligence to deal with records longer
than 512 bytes, however, so is forced to terminate records when that
limit is reached.  To compensate, so that spurious newlines do not get
inserted into lan{lisp} files, records exactly 512 long are assumed
to not actually be terminated, but "continued" with the next record, when
read as input.

kwd{:fixnum} simply uses fixed-length 512-byte records;  this is
what 7vasl* files use.


.section "Other File Operations"

.defun probe-file filename
If 2filename* can be opened, its truename is returned;  otherwise,
(false) is returned.  This may be used to see if 2filename*
exists.
.end_defun

Note fun_i{file-length} and fun_i{filepos} are missing from
lan{nil}.

All of the remaining functions in this section deal with either a
stream, or with a pathname.  For the former, they perform the
operation on the open stream;  for the latter, on the file in the
filesystem, which may involve opening the file temporarily.  At
present, none of them work on streams.  A future edition of the
filesystem code will contain more code written in lan{lisp}, and be
much more versatile in this regard.

For the functions which are described as returning an error
description, this is probably a string, but may change to be a more
complicated object in the future.  (That object should, however, have
the property that it will print with fun{princ} as the error
message.)  Tests made on the return result should be made accordingly;
that is, be based on fun{null}, or fun{streamp}, or fun{listp}
or whatever.  Signalled errors are typically signalled as proceedable
kwd{:io-lossage} errors;  returning a value from the error should
cause the function to return that as its value.

.defun rename-file file new-name &optional (error-p t)
Renames 2file*, a filename or a stream open to a file, to
2new-name*, which must be coercible to a pathname.  If
2error-p* is not (false), then a file-system error will be
signaled as a lan{lisp} error;  if it is (false), then an error
description will be returned.  If everything goes fine, (false) is
returned.
.end_defun

.defun delete-file file &optional (error-p t)
The file named by 2file*, or the file open on the stream
2file*, is deleted.  If an error occurs, then a lan{lisp} error
will be signaled if 2error-p* is not (false), otherwise an error
description will be returned.  If all goes well, (false) is
returned.
.end_defun

.defun file-creation-date file
This returns the creation date of the file as an integer in universal
time format ((time-package-section-page)), or (false) if this
cannot be determined.
.end_defun

.defun file-author file
Returns the name of the author of the file as a string, or (false).
For lan{vms} files, the string is a UIC, e.g. 3"[200,007]"*, and
the group and member numbers are guaranteed to be padded with leading
zeros to at least three digits.  (This will probably be changed to a
more program-understandable format in the future, such as a
dotted-pair of the group and member numbers.)
.end_defun


.section "File Matching"

.defun allfiles list-of-pathnames
Returns a list of pathnames matching all of those in
2list-of-pathnames*.  This is done, of course, by appending
together the lists of pathnames which match each of the pathnames in
2list-of-pathnames*.

By convention, this matches over all those components not specified in
each pathname.  lan{vms} does not allow matching all devices,
however, so the device should be specified, or will be defaulted from
somewhere (where?  rms default but it shouldn't be).  Newest versions
can be matched also, by using the appropriate pathname syntax.
Note that elipsis specifications in directories, and star
specifications in names, all work (fortuitously, perhaps, but they
work):  e.g., 3(allfiles "[nil...]286*.*;")* returns a list of
pathnames of the files with
highest version number of all the files in the lan{nil} hierarchy
with first three characters of their name being "286".
.end_defun

.defun mapallfiles function list-of-pathnames
Calls 2function* on each pathname which matches pathnames in
2list-of-pathnames*.  This is essentially equivalent to
.lisp
(mapc 2function* (allfiles 2list-of-pathnames*))
.end_lisp
but calls 2function* on each as it is generated rather than
consing up the list.

In fact, fun{allfiles} is implemented in terms of
fun{mapallfiles}.

Should i document the 3&rest 2args** this function takes,
which it passes in as extra arguments to 2function*?  Should they
be flushed as garbage?  This function is inherited from
lan{maclisp}, which doesn't support those extra args, and the fact
that in the argument list (to remain lan{maclisp} compatible) they
would be separated from the 2function* by the
2list-of-pathnames* arg might be confusing.
.end_defun

.defun directory list-of-pathnames &optional (kwdlist t)
3directory* works like 3allfiles*, but instead of returning a
list of pathnames, it returns a list of disembodied property lists.
The 3car* of each disembodied property list is the full name of
the file (like 3allfiles* returns), and the 3cdr* has
alternating keywords and values which are various attributes of the
files.  2kwdlist* should be a list of the keywords listing the
various attributes which should be returned;  if it is 3t* or
unspecified, then all of the attributes it can accept will be
returned.  The following keywords are accepted.  Note that not all of
them (or their formats) will be applicable in the future when
lan{nil} talks to foreign (non-lan{vms}) filesystems.
.table 3 250 250 0 0 0
.item :creation-date
The creation date of the file, in universal-time format.
Universal-time format is an integer number of seconds, and is
described in (time-package-section-page);  this implies that the
lan{vms}-supplied creation date, which is accurate to hundredths of
a second, is truncated.
.item :revision-date
Similar to 3:creation-date*.  This is the date-last-revised of the
file.
.item :revision-count
The revision count of the file.
.item :author
The file author.  This is returned as a string representation of the
UIC, e.g., "[200,010]".
.item :protection
A list representation of the protection mask of the file.  It is best
described by showing one:
.lisp
((:system :read :write :execute :delete)
 (:owner :read :write :execute :delete)
 (:group :read :write :execute)
 (:world :read :execute))
.end_lisp
The order of the entries within the list is guaranteed, and the order
of the keywords within each entry is guaranteed.  These orders are the
same as those used in lan{vms} directory listings, to make that sort
of conversion easy.
.item :blocks
The number of blocks in the file.
.item :allocation
The number of blocks allocated to the file.
.end_table
.end_defun

.defun mapdirectory function list-of-pathnames &optional (kwdlist t)
Analogous.
.end_defun

3allfiles*, 3mapallfiles*, 3directory*, and
3mapdirectory* all accept a single string/symbol/pathname in place
of a list, and are commonly used in this way.  It may be the case that
this will be the "accepted use" of them, and the list of pathnames
considered a lan{maclisp} compatibility feature.  As it is, the
3directory* function is not really compatible with lan{maclisp},
because every one of the keywords is incompatible.


.section "Loading Files"

.defun load filename &key :verbose :package :set-default-pathname :static :default-pathname :characters :binary :defaults :print
.table 3 250 250
.item :verbose
Boolean:  print out lots of gubbish about loading.  Default is value of
var{*load-verbose*}.
.item :package
override the package specification (if any) obtained from the file.
.item :set-default-pathname
Boolean:  set the default pathname of the pathname-defaults used (see
kwd{:defaults} and kwd{:default-pathname}, below).
Default is value of var{*load-set-default-pathname*}.
.item :defaults
Specified pathname-defaults to use in place of the value of
var{*load-pathname-defaults*}.  (This one isn't in lan{common
lisp}.  Not clear it should be heavily used, but i can see it has
application.)
.item :default-pathname
Use this for defaulting, in preference to the pathname-defaults.  The
defaults are still set in the defaults specified by kwd{:defaults}
(or its absence).
.item :characters
.item1 :binary
Boolean.  kwd{:binary t} implies that the file is a lan{vasl}
file;  lan{:characters t} implies that the file is lan{lisp} text.
By default, the file is examined to determine which it is.  And, if no
kwd{type} is specified in 2filename*, first a file with type
3vasl* and then a file with type 3lisp* will be looked for.
.item :static
Boolean;  says to load the file into the static heap.  Default is
value of var{*load-in-static-area*}.
.item :print
Boolean;  if not (false), says that the results of evaluation of
forms in the file are to be printed.  Default is (false), and it
probably doesn't work anyway;  certainly not for 3vasl* files.
.end_table
.end_defun


.section "Pathname Messages"


I was going to document the internal conventions, but they are
probably going to break with improvement in the error system.
Essentially, the messages for dealing with the filesystem like
msg_i{:rename}, msg_i{:delete}, msg{:creation-date}, msg{:author},
etc. currently return multiple values--the first being (false) or an
error description.  The remaining values are various informative
things about the operation, such as (for msg_i{:rename}) the
kwd{truename} of the 2from* file and the kwd{truename} of the
2to* file.  Error system changes will probably make them not
return error status, but only the other values, the errors being
hacked by signalling only.


.section "Internals for VMS Record Management Services"

.subsection "Data Structures"

See the NIL sopurce files RMSSTR and RMSSUB;  the file VMSFILE contains
some examples.

.defun si:make-fab
.end_defun
.defun si:make-rab
.end_defun
.defun si:make-nam
.end_defun
.defun si:make-xab
.end_defun

.defresource si:fab
.end_defresource

.defresource si:rab
.end_defresource
.defresource si:nam
.end_defresource
.defresource si:xab
.end_defresource

.subsection "RMS Hacking"

.defun si:rms$close fab
.end_defun

.defun si:rms$create fab
.end_defun

.defun si:rms$display fab
.end_defun

.defun si:rms$erase fab
.end_defun

.defun si:rms$extend fab
.end_defun

.defun si:rms$open fab
.end_defun

.defun si:rms$connect rab
.end_defun

.defun si:rms$delete rab
.end_defun

.defun si:rms$disconnect rab
.end_defun

.defun si:rms$find rab
.end_defun

.defun si:rms$flush rab
.end_defun

.defun si:rms$free rab
.end_defun

.defun si:rms$get rab
.end_defun

.defun si:rms$nxtvol rab
.end_defun

.defun si:rms$put rab
.end_defun

.defun si:rms$release rab
.end_defun

.defun si:rms$rewind rab
.end_defun

.defun si:rms$trunc rab
.end_defun

.defun si:rms$update rab
.end_defun

.defun si:rms$wait rab
.end_defun

.defun si:rms$read rab
.end_defun

.defun si:rms$space rab
.end_defun

.defun si:rms$write rab
.end_defun

.defun si:rms$enter fab
.end_defun

.defun si:rms$parse fab
.end_defun

.defun si:rms$remove fab
.end_defun

.defun si:rms$rename fab1 fab2
.end_defun

.defun si:rms$search fab
.end_defun


.defun si:rms$setddir new-directory-specification
Returns, and maybe updates, the lan{rms} default directory.  If
2new-directory-specification* is (false), the lan{rms} default
is not modified;  otherwise, it is set to
2new-directory-specification*, which must be a string.  This is a
fairly direct interface to the 7SYS$SETDDIR* system service.

If something goes wrong a system error status code may be returned
instead of a string.
.end_defun


.section "File Attribute Lists"
.setq file-attribute-section-page section-page
.setq file-attribute-list-section-page section-page
.setq file-plist-section-page section-page
.setq file-property-list-section-page section-page

Not too much detail yet...  However, it's necessary to use it.

If, on the first line of a source file the characters "-*-" appear,
then the text from the first "-*-" to the next is parsed as a
term_i{file attribute list}.  (Funnyness with multiple lines?  Well,
anyway, it works easily on one line.)  This text is logically a list
of keyword/value pairs, with the values being either single values or
lists of values.  The entire construct is made invisible to the
processing language by being placed within its commenting construct.
.lisp
; -*- Mode:Lisp; Package:Compiler; Base:10; Readtable:NIL -*-
.end_lisp
might occur as the first line in a lan{nil} compiler source file.
It says that the 3mode* of the file is 3lisp* (this being for
the benefit of text editors), and that the file should be read and
processed in the 3compiler* package, decimal radix, and using the
lan{nil} readtable.  "Lists" of values are provided for by
separating the individual items by commas, as in
.lisp
; -*-  Mode:Lisp;  LSB:ppdef,pretty-print-definition  -*-
.end_lisp
The parsing of tokens in such a construct is pretty rudimentary and
crufty, but essentially things are symbols except for a series of
digits (optionally followed by a decimal point) which is a decimal
integer.

File attributes typically translate into some special binding
environment needed for the processing of the file (in some context).
The following are pre-defined in lan{nil}:
.table 3 250 250
.item package 2package-name*
The file is processed in the package named 2package-name*.
.item readtable 2readtable-name*
The file is read in using the readtable named 2readtable-name*.
Syntax, and readtable naming, is described in (syntax-section-page).
.item base 2radix*
Binds both the input and output radices, no matter what those damned
variables are named.
.item radix 2radix*
For those who are confused by 3base* and will be even moreso when
the variable is named 3*base**.
.item patch-file 2yes-or-no*
If 2yes-or-no* is 3yes* (it shouldn't be specified otherwise),
then a variable proclaiming the patch-file-ness of this file is bound,
so that various things can see it and be clever, like the helpful
function which warns you about redefining a function defined by
someone else in another file (said function not existing yet).
.item lsb 2module-name*,2system-name*
This is defined by lan{lsb} ref{LSBMan}, not lan{nil} (q.v.).
.end_table

When a file attribute list is parsed, the attribute names are
keywords, and the values are either keywords or integers (or lists of
keywords or integers).

.defmessage :file-plist pathname
If 2pathname* can be opened, then this returns a disembodied
property list with the file attributes in the 3cdr*, and the
truename of the file in the 3car*.  Otherwise, it returns
(false).

This probably should be renamed 3:file-attribute-list*.
.end_defmessage

.defun fs:process-in-load-environment plist funct pathname &rest args
2plist* should be a parsed file attribute list (with an 2even*
number of elements;  the 3cdr* of what is returned by the
3:file-plist* message).  2pathname* should be the pathname
which the file attributes were obtained from.

The environment which is specified by that attribute list is
established, and then 2funct* called with arguments of
2pathname* and whatever 2args* were given.

This is what is used by both 3load* and the compiler.  It enables
a stable interface to how bindings and other environment modifications
are obtained from the file attributes.
.end_defun

Examination of the source code (the file 7[NIL.IO]PATHN.LSP*) will
show the convention which is used for defining additional file
attributes.  It is basically an extension of that defined by
lan{lisp machine lisp}.

