mirror of
https://github.com/PDP-10/its.git
synced 2026-01-13 15:27:28 +00:00
216 lines
8.7 KiB
Plaintext
Executable File
216 lines
8.7 KiB
Plaintext
Executable File
MacLISP NewIO Functions Kent M. Pitman, 21 Feb 1980
|
||
|
||
|
||
Opening/Closing and using file objects in New-I/O.
|
||
|
||
New I/O has the notion of a data object called a file. Files are actually
|
||
implemented as arrays, so if you get ahold of a file object and type
|
||
(TYPEP <thing>) it will answer "ARRAY", but there is another predicate
|
||
(FILEP <thing>) that should return T in the case of files and not for other
|
||
arrays.
|
||
|
||
File objects are created by the open command. The open command takes
|
||
the following syntax (both arguments optional).
|
||
|
||
(OPEN [<filespec> [ <options> ]])
|
||
|
||
<filespec> must evaluate to either a NAMESTRING or a NAMELIST.
|
||
The default file is the value of the variable DEFAULTF.
|
||
|
||
<options> must evaluate to a list of atoms specifying the modes to open
|
||
the file in. The default is '(IN ASCII DSK BLOCK).
|
||
|
||
Possible options are:
|
||
Direction - either IN (or READ), OUT (or PRINT), APPEND
|
||
|
||
Data mode - either ASCII, FIXNUM (bastard image mode),
|
||
or IMAGE (really super-image).
|
||
Device type - TTY or DSK
|
||
Buffering mode - BLOCK or SINGLE
|
||
Echo mode - Open in echo area of tty only (this works only
|
||
in ITS MACLISP)
|
||
|
||
This operation opens a file and creates an object which knows what is
|
||
going on with respect to the file. Each time you open a file, a new
|
||
file object is created (except under certain conditions to be detailed
|
||
later). Multiple file objects may be open to a file by the same name.
|
||
If they are reading the file, they will all have pointers to the same file.
|
||
If they are writing to the file, they will all have pointers to different
|
||
files, and the file object which is closed last will be the one which
|
||
becomes the file named. A file opened for write cannot be opened by
|
||
anyone else (including DDT's print). It MUST be closed first.
|
||
|
||
To close a file, the syntax is merely (CLOSE <object>) where <object>
|
||
must be a form that evaluates to a file object (the thing returned by
|
||
the OPEN request). Note that the thing returned from the open request
|
||
does not get stored anywhere automatically so make sure you setq some
|
||
variable to it or you will not be able to do anything with it! File
|
||
objects with no pointers to them are closed and recycled the next time
|
||
a garbage collection is done.
|
||
|
||
Most input/output commands default to the tty and accept optional file
|
||
objects as a last arg. Examples are:
|
||
|
||
(TYO <n> [ <file-object> ]) ; Output ascii char corresponding to <n>
|
||
; on <file-object> if given, else tty.
|
||
|
||
(TYI [ <file object> ]) ; Return the fixnum value of next character seen
|
||
; on <file-object> if given, else tty.
|
||
|
||
(PRINT <exp> [ <file-object> ]) ; Use lisp normal printer to display <exp>
|
||
; on <file-object> if given, else tty.
|
||
|
||
READ, READLINE, IN, OUT, PRINC, PRIN1, and so on all work in analagous ways.
|
||
|
||
Most commands that are for inputing from a file also allow an optional
|
||
arg following the file object which is the value to be returned if there
|
||
is an end of file.
|
||
|
||
Thus you can also say:
|
||
|
||
(SETQ UNIQUE (GENSYM))
|
||
(READ <file-object> UNIQUE)
|
||
|
||
and if an end of file condition occurs during the real (ie, the read fails),
|
||
then the last arg (UNIQUE in above example) will be returned. If the read
|
||
happens to touch the end of the buffer but is still successful, the end
|
||
of file value will not be returned. TYI and TYIPEEK require that the
|
||
end-of-file value be a fixnum (-1. is a good choice - especially since
|
||
TYIPEEK is broken at the time I am writing this and it will return -1.
|
||
regardless of what you say if an end of file is hit.)
|
||
|
||
Note: The end of file condition on the tty cannot happen in tyi/tyipeek
|
||
but can happen in READ and READLINE and is defined to happen
|
||
if there is an over-rubout.
|
||
|
||
If an end-of-file is reached and there is no form to return (ie, the
|
||
optional arg was omitted) an error results if there is also not an
|
||
EOF function... (What's an EOF function?)
|
||
|
||
The function (EOFFN <file-object> [ <optional-function-spec> ]) is a
|
||
function that reads or sets the eoffn (End Of File FuNction) for a
|
||
file-object. If the EOFFN is null (default) then an error will happen
|
||
if there is an eof condition is reached.
|
||
|
||
(EOFFN <file-object>) tells you what <file-object>'s related End of file
|
||
function is.
|
||
|
||
(EOFFN <file-object> <function-name-or-lambda>) sets <file-object>'s
|
||
eoffn.
|
||
|
||
The EOFFN must be a function of two args:
|
||
arg1= the stream on which the end-of-file has happened.
|
||
arg2= the value that the user expected returned (optional last value
|
||
or default last value (NIL for READ and READLINE, -1 for TYI
|
||
and TYIPEEK, etc.))
|
||
|
||
The file will be closed automatically by lisp when an end-of-file
|
||
is read and before the eof function has been called (if any) or the
|
||
eof value returned. A common kind of EOF function is one which re-opens
|
||
the file object. A file object may be re-opened in the identical modes
|
||
it was opened the first time by just saying (OPEN <file-object>).
|
||
|
||
File specifications may take on the following formats:
|
||
|
||
((device directory) filename1 filename2) ; Namelist
|
||
|
||
|device: directory; filename1 filename2| ; Namestring
|
||
|
||
with * being used as a wildcard (means use the default, NOT match all files).
|
||
The default file is stored in DEFAULTF. It should never be altered by
|
||
(SETQ DEFAULTF ...) but rather the function DEFAULTF of one arg should be
|
||
used. It will ensure that the right syntax is used.
|
||
|
||
Eg, if DEFAULTF evals to ((DSK FOO) BAZ >) and the user does:
|
||
(DEFAULTF '(FOO BAR))
|
||
DEFAULTF is now => ((DSK FOO) FOO BAR)
|
||
(DEFAULTF 'BOX)
|
||
DEFAULTF => ((DSK FOO) BOX BAR)
|
||
(DEFAULTF '((BAZ)))
|
||
DEFAULTF => ((DSK BAZ) BOX BAR)
|
||
(DEFAULTF '((AI)))
|
||
DEFAULTF => ((AI BAZ) BOX BAR) ; DEFAULTF is smart about devices
|
||
(DEFAULTF '((FOO) * BAX))
|
||
DEFAULTF => ((AI FOO) BOX BAX)
|
||
|
||
and so on...
|
||
|
||
There is a general command that you can call to merge to filenames.
|
||
It is called MERGEF and is what is used by DEFAULTF. Thus saying
|
||
(MERGEF '|HI THERE| '((FOO BAR) BAZ GUNK)) will return
|
||
((FOO BAR) HI THERE).
|
||
|
||
Other useful commands are which work on all of [namelists, namestrings,
|
||
file-objects] are:
|
||
|
||
(NAMELIST <file>) ; give namelist form of file
|
||
|
||
(NAMESTRING <file>) ; give namestring form of file
|
||
|
||
(SHORTNAMESTRING <file>) ; give only filename1 and filename2
|
||
; parts of namestring
|
||
|
||
NOTE: The namestring format on non-ITS sites allows the appropriate
|
||
filenaming conventions for the operating system being run under.
|
||
eg, for Twenex, |<FOO>BAR.BAZ.3| would be an appropriate
|
||
namestring.
|
||
|
||
(PROBEF <file>) ; returns NIL if file doesn't exist, and the true name
|
||
; of the file as a namelist if it does exist.
|
||
|
||
(DELETEF <file>) ; deletes the file
|
||
|
||
(RENAMEF <file> <filename>) ; renames the <file> to <filename>
|
||
|
||
The following are kind of special purpose things:
|
||
|
||
(CNAMEF <closed-file-object> <new-name>)
|
||
This command will take a file object which must be closed, and
|
||
rename it so that when you call OPEN on it, you'll be opening
|
||
a different file. This helps cope with the problem that you can
|
||
only create some fixed number of open streams (like 13 or so)
|
||
on ITS, and if you have used all the file streams but have one
|
||
you want to recycle, you can do a CNAMEF.
|
||
|
||
(ENDPAGEFN <file-object> [ <end-page-function> ])
|
||
When a page-end occurs on a stream it is non-fatal and will
|
||
just be ignored unless an endpage handler has been specified.
|
||
There is a default ENDPAGEFN for TYO (the default tty output
|
||
stream) which causes the ##MORE## at the bottom of a page.
|
||
This is similar in use to EOFFN.
|
||
|
||
Notes on variables:
|
||
|
||
TYO - Should always have the tty output object in it.
|
||
TYI - Should always have the tty input object in it.
|
||
|
||
|
||
(CURSORPOS [ <data> ] [ <tty-file-object> ])
|
||
|
||
If <data> is omitted, the cursorposition on <tty-file-object> (or the
|
||
default output file if this is missing) is returned as
|
||
( <vertical-pos> . <horizontal-pos> ) -- 0-indexed.
|
||
|
||
If <data> is given it is of one of the following forms:
|
||
|
||
<char> - send a <char> to the tty - see .INFO.;LISP CURSOR
|
||
for full description of what options there are.
|
||
<char> <val> - same as <char> - some chars need extra data.
|
||
<vpos> <hpos> - move to position ( <vpos> . <hpos> )
|
||
NIL <hpos> - move to <vpos> on current line - same as 'H <hpos>
|
||
<vpos> NIL - move to <vpos> (same <hpos>) - same as 'V <vpos>
|
||
NIL NIL - stay where you are (?)
|
||
|
||
|
||
------------------------------------------------------------------------------
|
||
|
||
There is also a function called LOAD which will read and execute a file
|
||
as a unit. If the file is a FASL file, it will be fasloaded, else it will
|
||
forms will be read and eval'd from it sequentially as if it had been typed
|
||
at the terminal. (Default input is bound during such a read so that commands
|
||
like (TYI) ore (READ) at toplevel with no file-spec argument will be read
|
||
from the file rather than from the terminal.) The syntax for the command
|
||
is just (LOAD <filename>) where <filename> should evaluate to a namelist,
|
||
namestring, or file object.
|
||
|