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 ) it will answer "ARRAY", but there is another predicate (FILEP ) 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 [ [ ]]) must evaluate to either a NAMESTRING or a NAMELIST. The default file is the value of the variable DEFAULTF. 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 ) where 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 [ ]) ; Output ascii char corresponding to ; on if given, else tty. (TYI [ ]) ; Return the fixnum value of next character seen ; on if given, else tty. (PRINT [ ]) ; Use lisp normal printer to display ; on 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 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 [ ]) 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 ) tells you what 's related End of file function is. (EOFFN ) sets '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 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 ) ; give namelist form of file (NAMESTRING ) ; give namestring form of file (SHORTNAMESTRING ) ; 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, |BAR.BAZ.3| would be an appropriate namestring. (PROBEF ) ; returns NIL if file doesn't exist, and the true name ; of the file as a namelist if it does exist. (DELETEF ) ; deletes the file (RENAMEF ) ; renames the to The following are kind of special purpose things: (CNAMEF ) 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 [ ]) 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 [ ] [ ]) If is omitted, the cursorposition on (or the default output file if this is missing) is returned as ( . ) -- 0-indexed. If is given it is of one of the following forms: - send a  to the tty - see .INFO.;LISP CURSOR for full description of what options there are. - same as - some chars need extra data. - move to position ( . ) NIL - move to on current line - same as 'H NIL - move to (same ) - same as 'V 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 ) where should evaluate to a namelist, namestring, or file object.