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.

