{Begin SubSec Files} {Title Files} {Text {index *BEGIN* files} {index *BEGIN* opening files} All input/output functions in Interlisp can specify their source/destination file with an argument (frequently optional) that usually must designate an {it open} file. Files are opened and manipulated by the functions described below. The name {lisp T} designates terminal input and output, and is always considered open. If the file argument is {lisp NIL} or defaulted, it designates either the files that have been established as "primary input" or "primary output". Currently, it possible to supply a string as an input "file" without explicitly opening it; input operations will read successive characters from the string. Note that because of this feature, file names must always be specified as litatoms, not strings. {FnDef {FnName OPENFILE} {FnArgs FILE ACCESS RECOG BYTESIZE PARAMETERS} {Text Opens {arg FILE} with access rights as specified by {arg ACCESS}, one of {lisp INPUT}, {lisp OUTPUT}, {lisp BOTH}, or {lisp APPEND}, and returns the full name of the file. Causes error {index FILE NOT FOUND Error}{lisp FILE NOT FOUND} if {arg FILE} is not recognized by the file system, or other errors if {arg FILE} is recognized but cannot be opened, e.g. {lisp FILE WON'T OPEN}{index FILE WON'T OPEN Error} if the file is already opened by someone else or is protected against the operation, {lisp FILE SYSTEM RESOURCES EXCEEDED}{index FILE SYSTEM RESOURCES EXCEEDED Error} if there is no more room in the file system. For {arg ACCESS}={lisp INPUT}, only input operations are permitted on the file; for {arg ACCESS}={lisp OUTPUT} or {arg ACCESS}={lisp APPEND}, only output operations are permitted. Note: in Interlisp-10 and Interlisp-D, {arg ACCESS}={lisp OUTPUT} implies that one intends to write a new or different file, even if a version number was specified and the corresponding file already exists. Thus any previous contents of the file are discarded, and the file is empty immediately after the {fn OPENFILE}. If it is desired to write on an already existing file while preserving the old contents, the file must be opened for access {lisp BOTH} or {lisp APPEND}. {arg RECOG} specifies the recognition mode of {arg FILE}, as described on {PageRef fn FULLNAME}. If {arg RECOG}={lisp NIL}, it defaults according to the value of {arg ACCESS}: for {arg ACCESS}={lisp INPUT}, {arg RECOG}={lisp OLD} is used; for {arg ACCESS}={lisp OUTPUT}, {arg RECOG}={lisp NEW} is used; for the other values of {arg ACCESS}, {arg RECOG}={lisp OLD/NEW} is used. {arg BYTESIZE}, if supplied, is the byte size in which to open the file. If {arg BYTESIZE}={lisp NIL}, the bytesize used is the default for the implementation (8 for Interlisp-D, 7 for Interlisp-10). {arg PARAMETERS} is a list specifying additional opening parameters. In Interlisp-10, this list may contain the following litatoms: {Begin Labeledlist opening parameters} {Indent 15percent} {Label {lisp WAIT}} {Text Wait if file is busy.} {Label {lisp DON'T.CHANGE.DATE}} {Text Don't change the access dates.} {Label {lisp THAWED}} {Text Open file in "thawed" mode.} {End Labeledlist opening parameters} In Interlisp-D, {arg PARAMETERS} must be a list of pairs {lisp ({arg ATTRIB} {arg VALUE})}, where {arg ATTRIB} is any file attribute that the file system is willing to allow the user to set (see {fn SETFILEINFO}, {PageRef Fn SETFILEINFO}). A non-list {arg ATTRIB} in {arg PARAMETERS} is treated as the pair {lisp ({arg ATTRIB} {lisp T})}. }} If the {arg FILE} argument to an input (output) function is not given (has value {lisp NIL}), the file specified as "primary" for input (output) is used. Initially, these are both {lisp T}, for {index terminal}terminal input and output. However, the primary input or output file may be changed with the functions below. {index *PRIMARY* primary input file} {index *PRIMARY* primary output file} {FnDef {FnName INPUT} {FnArgs FILE} {Text Sets {arg FILE} as the primary input file; returns the name of the old primary input file. {arg FILE} must be open for input. {fn INPUT} can also be given a string as argument, interpreted as described above. {lisp (INPUT)} returns the current primary input file, which is not changed. }} {FnDef {FnName OUTPUT} {FnArgs FILE} {Text Sets {arg FILE} as the primary output file; returns the name of the old primary output file. {arg FILE} must be open for output. A string cannot be used as an output file. {lisp (OUTPUT)} returns the current primary output file, which is not changed. }} {FnDef {FnName INFILE} {FnArgs FILE} {Text Opens {arg FILE} for input, and sets it as the primary input file. Equivalent to {lisp (INPUT (OPENFILE {arg FILE} 'INPUT 'OLD))} }} {FnDef {FnName OUTFILE} {FnArgs FILE} {Text Opens {arg FILE} for output, and sets it as the primary output file. Equivalent to {lisp (OUTPUT (OPENFILE {arg FILE} 'OUTPUT 'NEW))}. }} {FnDef {FnName IOFILE} {FnArgs FILE} {Text {lisp (OPENFILE {arg FILE} 'BOTH 'OLD)}; opens {arg FILE} for both input and output. Does not affect the primary input or output file. }} {FnDef {FnName OPENP} {FnArgs FILE ACCESS} {Text If {arg ACCESS}={lisp NIL}, returns the full name of {arg FILE} if {arg FILE} is open either for input or for output; otherwise {lisp NIL}. If {arg ACCESS} is {lisp INPUT}, {lisp OUTPUT} or {lisp BOTH}, returns the full name of {arg FILE} if it is open in that access mode; otherwise {lisp NIL}. Note: If {arg FILE} is not recognized, {fn OPENP} returns {lisp NIL} without generating an error. {lisp (OPENP)} returns a list of all files open for input or output, excluding {lisp T} and the current typescript (dribble) file, if any ({PageRef Tag DribbleFiles}). }} {FnDef {FnName CLOSEF} {FnArgs FILE} {Text Closes {arg FILE}. Generates an error, {lisp FILE NOT OPEN}{index FILE NOT OPEN Error}, if {arg FILE} is not open. If {arg FILE} is {lisp NIL}, it attempts to close the primary input file{index primary input file} if other than terminal. Failing that, it attempts to close the primary output file{index primary output file} if other than {index terminal}terminal. Failing both, it returns {lisp NIL}. If it closes any file, it returns the name of that file. If it closes either of the primary files, it resets that primary file to terminal. {fn WHENCLOSE} ({PageRef Fn WHENCLOSE}) allows the user to "advise" {fn CLOSEF} to perform various operations when a file is closed. }} {FnDef {FnName CLOSEF?} {FnArgs FILE} {Text Closes {arg FILE} if it is open, otherwise does nothing. Returns {arg FILE}. }} {FnDef {FnName CLOSEALL} {FnArgs ALLFLG} {Text Closes all open files, except {lisp T} and the current typescript file, if any. Returns a list of the files closed. {fn WHENCLOSE} ({PageRef Fn WHENCLOSE}) allows certain files to be "protected" from {fn CLOSEALL}. {lisp (CLOSEALL T)} overrides this protection. }} {FnDef {FnName DELFILE} {FnArgs FILE} {Text Deletes {arg FILE} if possible. Returns {arg FILE} if deleted, else {lisp NIL}. }} {FnDef {FnName RENAMEFILE} {FnArgs OLDFILE NEWFILE} {Text Renames {arg OLDFILE} to be {arg NEWFILE}. Returns {arg NEWFILE} if successful, else {lisp NIL}. In the general case (e.g., when {arg OLDFILE} and {arg NEWFILE} are on different devices), {fn RENAMEFILE} works by copying {arg OLDFILE} to {arg NEWFILE} and then deleting {arg OLDFILE}. }} {index *END* opening files} {Begin SubSec File Naming and Recognition} {Title File Naming and Recognition} {Text {index *PRIMARY* file names} In Interlisp, a file name is a literal atom composed of one or more {it fields}, separated by suitable punctuation. The precise fields and their interpretation is dependent on the implementation; the functions {fn PACKFILENAME} and {fn UNPACKFILENAME} ({PageRef fn PACKFILENAME}) are used to construct and take apart filenames in an implementation-independent way. Depending on the file system implementation, file names given to input/output functions may be incompletely specified, with the file system handling the task of obtaining a specific file from a partial name, or {it recognizing} the file. For example, in file systems that support version numbers, one can call {fn OPENFILE} giving a file name without a version number, and the file system will supply a default version number based on the context (opening a new file for output vs. an old file for input). Internally, however, each open file has associated with it a completely-specified filename, one that uniquely identifies the file to the file system in any context. It is this "full" file name that is returned from {fn OPENFILE} and other functions that return names of open files. For example, {lisp (OPENFILE 'FOO 'OUTPUT)} might return {lisp FOO.;3}. Any time that an input/output function is called with a file name other than the full file name, Interlisp must perform recognition on the partial file name in order to determine which open file is intended. Thus if repeated operations are to be performed, it is considerably more efficient to use the full file name returned from {fn OPENFILE} than to repeatedly use the possibly incomplete name that was used to open the file. In Interlisp-10, filenames follow the conventions of the operating system (either TENEX or TOPS-20), i.e., {arg FILE} can be prefixed by a directory name enclosed in angle brackets, can contain s{index $ ()} or control-F's,{index control-F (in file name) Term} and can include suffixes and/or version numbers.{index version numbers} When a file is opened for input and no version number is given, the highest existing version number is used. Similarly, when a file is opened for output and no version number is given, a new file is created with a version number one higher than the highest one currently in use with that file name. The full filename in Interlisp-10 consists of directory, name, extension, and version. In Interlisp-D, it also includes a device or host name in brackets, i.e, {lisp {bracket PHYLUM}FOO.;3}). The following functions can be used to perform file recognition without opening a file: {it Warning: For some file devices (e.g., on a remote host), it isn't possible to determine the full name of a file without trying to open it. In this case, {fn OUTFILEP} and {fn FULLNAME} may not always return the correct value. For example, a remote host may either not support the operation; on a time-sharing system, there is a possibility that the file system would change between the call to {fn OUTFILEP} any actual opening of the file. Thus, {fn OUTFILEP} and {fn FULLNAME} can only be treated as a "best guess". } {FnDef {FnName INFILEP} {FnArgs FILE} {Text Returns full file name of {arg FILE} if {arg FILE} is recognized as specifying the name of an existing file that could potentially be opened for input, {lisp NIL} otherwise. Recognition is in input context, i.e., if no version number is given, the highest existing version number is returned. }} {FnDef {FnName OUTFILEP} {FnArgs FILE} {Text Similar to {fn INFILEP}, except recognition is in output context, i.e., in Interlisp-10, if no version number is given, a version number one higher than the highest existing version number is returned. Roughly speaking, {fn OUTFILEP} returns the full name of the file that would be created if {fn OUTFILE} were called with the same argument. }} A more general version of {fn INFILEP} and {fn OUTFILEP} is provided by the function {fn FULLNAME}: {index file names} {index full file name} {FnDef {FnName FULLNAME} {FnArgs X RECOG} {Text If {arg X} is recognized in the recognition mode specified by {arg RECOG} as an abbreviation for some file, returns the file's full name, otherwise {lisp NIL}. {arg RECOG} can be {lisp OLD}, meaning choose the (newest) existing version of the file; {lisp NEW}, meaning make the full file name one which does not yet exist (version number one higher than highest existing version); {lisp OLDEST}, meaning choose the existing file with the lowest version number; or {lisp OLD/NEW}, meaning to recognize an existing version if possible, otherwise a new version (useful only for writing a file). {arg RECOG}={lisp NIL} defaults to {lisp OLD}. For all other values of {arg RECOG}, generates an error {lisp ILLEGAL ARG}.{index ILLEGAL ARG Error} If {arg X} is not a literal atom, generates an error, {index ARG NOT LITATOM Error}{lisp ARG NOT LITATOM}. For example, {fn INFILEP} could be defined as {lisp (FULLNAME {arg FILE} 'OLD)} and {fn OUTFILEP} as {lisp (FULLNAME {arg FILE} 'NEW)}. The {arg RECOG} argument is used only for defaulting unspecified parts of the filename (in Interlisp-10 and Interlisp-D, the version), not to pass judgment on the specified parts. In particular, {arg RECOG}={lisp NEW} does not require that the file be new. For example, {lisp (FULLNAME 'FOO.;2 'NEW)} may return {lisp FOO.;2} if that file already exists, even though {lisp (FULLNAME 'FOO 'NEW)} would default the version to a new number, perhaps returning {lisp FOO.;5}. }} Note that {fn INFILEP}, {fn OUTFILEP} and {fn FULLNAME} do not open any files, or change the primary files; they are pure predicates. In general they are also only hints, as they do not necessarily imply that the caller has access rights to the file. For example, {fn INFILEP} might return non-{lisp NIL}, but {fn OPENFILE} might fail for the same file because the file is read-protected against the user, or the file happens to be open for output by another user at the time. Similarly, {fn OUTFILEP} could return non-{lisp NIL}, but {fn OPENFILE} could fail with a {lisp FILE SYSTEM RESOURCES EXCEEDED}{index FILE SYSTEM RESOURCES EXCEEDED Error} error. Note also that in a multi-user file system, intervening file operations by another user could contradict the information returned by recognition. For example, a file that was {fn INFILEP} might be deleted, or between an {fn OUTFILEP} and the subsequent {fn OPENFILE}, another user might create a new version or delete the highest version, causing the names returned by {fn OUTFILEP} and {fn OPENFILE} to have different version numbers. Thus, in general, the "truth" about a file can only be obtained by actually opening the file; in particular, creators of files should rely on the name returned from {fn OPENFILE}, not from {fn OUTFILEP}. If the file system does not successfully recognize an incomplete file name, a {lisp FILE NOT FOUND}{index FILE NOT FOUND Error} error is generated (except for {index INFILEP FN}{fn INFILEP}, {index OUTFILEP FN}{fn OUTFILEP}, {index FULLNAME FN}{fn FULLNAME} and {index OPENP FN}{fn OPENP}, which in this case return {lisp NIL}). As described on {PageRef Var ERRORTYPELST}, before a {lisp FILE NOT FOUND} error occurs, it is intercepted via an entry on {var ERRORTYPELST}{index ERRORTYPELST Var}, which causes {fn SPELLFILE}{index SPELLFILE FN} ({PageRef Fn SPELLFILE}) to be called. {fn SPELLFILE} will search alternate directories and possibly attempt spelling correction on the file name. Only if {fn SPELLFILE} is unsuccessful will the error actually occur. {index file names} Note that recognition is performed on the user's entire directory, not just the open files, which can result in certain anomalies. Thus, even if only one file is open, say {lisp FOO.;1}, the name {lisp F$} ({lisp F}) will not be recognized if the user's directory also contains the file {lisp FIE.;1}. Similarly, it is possible for a file name that was previously recognized to become ambiguous. For example, a program performs {lisp (INFILE 'FOO)}, opening {lisp FOO.;1}, and reads several expressions from {lisp FOO}. Then the user interrupts the program, creates a {lisp FOO.;2} and reenters his program. Now a call to {fn READ} giving it {lisp FOO} as its {arg FILE} argument will generate a {lisp FILE NOT OPEN}{index FILE NOT OPEN Error} error, because {lisp FOO} will be recognized as {lisp FOO.;2}. }{End SubSec File Naming and Recognition} {Begin SubSec Manipulating File Names} {Title Manipulating File Names} {Text {index *BEGIN* file names} {index *BEGIN* manipulating file names} Different operating systems have different conventions for naming files. However, it is desirable for Interlisp to be as implementation independent as possible. Therefore, all programs that need to reference parts of a filename, or construct new file names from existing ones, should use the functions described below. The implementation of these functions obviously is dependent on the operating system they will run under, but as far as the programs that use them are concerned, they permit expressing operations that are implementation independent.{foot In particular, the Interlisp-10 implementation recognizes file names in both Tenex and TOPS-20 format, and builds new names as appropriate. }{comment endfootnote} Every file name is composed of a collection of {it fields} which have different semantic interpretations. A {it field name} is a literal atom which is the name of a file-name field. Interlisp assumes that {lisp NAME} and {lisp EXTENSION} are valid field names; the implementor is free to allow other fields. In Interlisp-10, allowable field names are: {lisp DEVICE}, {lisp DIRECTORY}, {lisp NAME}, {lisp EXTENSION}, {lisp VERSION}, {lisp PROTECTION}, {lisp ACCOUNT}, and {lisp TEMPORARY}. Interlisp-D allows {lisp HOST}, {lisp DIRECTORY}, {lisp NAME}, {lisp EXTENSION}, and {lisp VERSION}. {FnDef {FnName FILENAMEFIELD} {FnArgs FILENAME FIELDNAME} {Text Returns the contents of the {arg FIELDNAME} field of {arg FILENAME}. }} {FnDef {FnName UNPACKFILENAME} {FnArgs FILENAME {anonarg}} {Text Returns a list of alternating field names and field contents. Examples from Interlisp-D: {lispcode _ (UNPACKFILENAME 'FOO.BAR) (NAME FOO EXTENSION BAR) _ (UNPACKFILENAME '{bracket PHYLUM}LISP>IMTRAN.DCOM;21) (HOST PHYLUM DIRECTORY SANNELLA>LISP NAME IMTRAN EXTENSION DCOM VERSION 21)} Examples from Interlisp-10 on Tenex: {lispcode _ (UNPACKFILENAME 'MAC.COM;3) (DIRECTORY LISP NAME MAC EXTENSION COM VERSION 3) _ (UNPACKFILENAME 'WORK.;T) (NAME WORK EXTENSION NIL TEMPORARY T)} Note: In Interlisp-10, {lisp (UNPACKFILENAME 'DSK:FOO)} returns {lisp (DEVICE DSK: NAME FOO)}, i.e. the {lisp :} is left in. This is so {lisp (DEVICE NIL:)} may be distinguished from {lisp (DEVICE NIL)}. {note currently, UNPACKFILENAME is the same on Interlisp-D and -10, so it will unpack ;T, etc, without giving an error, even in systems where such files cannot exist. bug or feature?} }} {FnDef {FnName PACKFILENAME} {FnArgs FIELDNAME{SUB 1} FIELDCONTENTS{SUB 1} {ellipsis} FIELDNAME{SUB N} FIELDCONTENTS{SUB N}} {Type NOSPREAD} {Text Takes a list of alternating field names and field contents (atoms or strings), and returns the corresponding file name. For example, {lisp (PACKFILENAME 'DIRECTORY 'LISP 'NAME 'NET)} returns {lisp NET}. If the same field name is given twice, the {it first} occurrence is used. If the "field name" {lisp BODY} is given, this means that the operand to {lisp BODY} should itself be unpacked and spliced into the argument list at that point. This is useful for providing default field names, or to change just one field in an existing name. For example, to take a file name {arg FILE} and change the {lisp DIRECTORY} field, perform {lisp (PACKFILENAME 'DIRECTORY {arg NEWDIRECTORY} 'BODY {arg FILE})}. Alternatively, to provide a default for the {lisp EXTENSION} field, perform {lisp (PACKFILENAME 'BODY {arg FILE} 'EXTENSION {arg DEFAULT})}. This uses {arg DEFAULT} as the extension unless one is already specified in {arg FILE}. Note that a null field is a field that {it has} been specified, e.g., if {arg FILE}={lisp FOO;1} in the above example, the default extension will be used, but if {arg FILE}={lisp FOO.;1}, it will not, because a null extension has been specified. If the first argument to {fn PACKFILENAME} is a list, {fn PACKFILENAME} is called on that argument. Thus {fn PACKFILENAME} and {fn UNPACKFILENAME} operate as inverses. }} {index *END* file names} {index *END* manipulating file names} }{End SubSec Manipulating File Names} {Begin SubSec File Attributes} {Title File Attributes} {Text {index *BEGIN* file attributes} Any file has a number of "file attributes", such read date, protection, and bytesize. The exact attributes that a file can have is implementation-dependent. The functions {fn GETFILEINFO} and {fn SETFILEINFO} allow the user to conveniently access file attributes: {note {fn GETFILEINFO} and {fn SETFILEINFO} were written by R. M. Kaplan and J. J. Vittal.} {FnDef {FnName GETFILEINFO} {FnArgs FILE ATTRIB} {Text Returns the current setting of the {arg ATTRIB} attribute of {arg FILE}. In Interlisp-10, {arg FILE} may also be a {lisp JFN} as returned by {fn GTJFN} ({PageRef Fn GTJFN}). In Interlisp-10, {fn GETFILEINFO} takes an optional third argument, {arg SCRATCH}, which is analogous to the third argument of {fn GDATE} ({PageRef fn GDATE}): a string pointer to reuse for those {arg ATTRIB}'s which return string values. }} {FnDef {FnName SETFILEINFO} {FnArgs FILE ATTRIB VALUE} {Text Sets the attribute {arg ATTRIB} of {arg FILE} to be {arg VALUE}. {fn SETFILEINFO} returns {lisp T} if it is able to change the attribute {arg ATTRIB}, and {lisp NIL} if unsuccessful (some attributes cannot be changed, e.g. the {lisp CREATIONDATE}). }} {fn GETFILEINFO} and {fn SETFILEINFO} currently recognize the following values for {arg ATTRIB}: {Begin LabeledList values for ATTRIB} {Label {lisp ACCESS}} {Text The current access mode of {arg FILE} (e.g. {lisp INPUT}, {lisp OUTPUT}, {lisp BOTH}, {lisp APPEND}) or {lisp NIL} if {arg FILE} is not open.} {Label {lisp BYTESIZE}} {Text The byte size of the file.} {Label {lisp LENGTH}} {Text The byte position of the end-of-file. Like {lisp (GETEOFPTR {arg FILE})}, but {arg FILE} does not have to be open.} {Label {lisp SIZE}} {Text The size of {arg FILE} in pages.} {Label {lisp WRITEDATE}, {lisp READDATE}, {lisp CREATIONDATE}} {Text The date (and time) as a string that {arg FILE} was respectively last written, last read, and originally created.} {Label {lisp IWRITEDATE}, {lisp IREADDATE}, {lisp ICREATIONDATE}} {Text The respective date in integer form, as {fn IDATE} ({PageRef Fn IDATE}) would return.} {Label {lisp AUTHOR}} {Text The user who last wrote the file.} {Label {lisp TYPE}} {Text (Interlisp-D) Either {lisp TEXT} or {lisp BINARY}.} {Label {lisp OPENBYTESIZE}} {Text (Interlisp-10) It is possible that the byte size for the "opening" of a file might differ from the "permanent" bytesize. For example, a 7-bit text file can be opened in 36-bit mode. To obtain the "open" bytesize, use attribute {lisp OPENBYTESIZE}.} {Label {lisp PROTECTION}} {Text (Interlisp-10) The "protection code" of {arg FILE}, as an integer.} {Label {lisp DELETED}} {Text (Interlisp-10) {lisp T} if {arg FILE} is the name of a deleted file, {lisp NIL} otherwise.} {Label {lisp EOL}} {Text The end-of-line convention for the file. This can be {lisp CR}, {lisp LF}, or {lisp CRLF}, indicating what sequences of characters on a file are converted to the implementation-dependent {lisp EOL} character when atoms and strings are read or printed.} {End LabeledList values for ATTRIB} Additional attributes which are available for Interlisp-10 on TOPS-20 systems (DEC release 4 or later) are: {Begin LabeledList values for ATTRIB on TOPS-20 systems} {Label {lisp INVISIBLE}} {Text {lisp T} if {arg FILE} has the invisible attribute, {lisp NIL} otherwise.} {Label {lisp ARCHIVED}} {Text {lisp T} if {arg FILE} has been archived, {lisp NIL} otherwise.} {Label {lisp OFF-LINE}} {Text {lisp T} if the contents of {arg FILE} are off-line (i.e. {arg FILE} has been archived and its contents flushed), {lisp NIL} otherwise.} {End LabeledList values for ATTRIB on TOPS-20 systems} {FnDef {FnName POSITION} {FnArgs FILE N} {Text Returns the column number at which the next character will be read or printed. After a end of line, the column number is 0. If {arg N} is non-{lisp NIL}, {it resets} the column number to be {arg N}. Note that {lisp (POSITION {arg FILE})} is {it not} the same as {lisp (GETFILEPTR {arg FILE})} which gives the position in the {it file}, not on the {it line}. }} {FnDef {FnName LINELENGTH} {FnArgs N FILE} {Text Sets the length of the print line for the output file {arg FILE} to {arg N}; returns the former setting of the line length. {arg FILE} defaults to the primary output file. {lisp (LINELENGTH NIL {arg FILE})} returns the current setting for {arg FILE}. When a file is first opened, its linelength is set to the value of the variable {var FILELINELENGTH}. Whenever printing an atom or string would increase a file's position {it beyond} the line length of the file, an end of line is automatically inserted first. This action can be defeated by using {fn PRIN3} and {fn PRIN4} ({PageRef Fn PRIN3}). }} {FnDef {FnName SETLINELENGTH} {FnArgs N} {Text In Interlisp-10,if {arg N} is {lisp NIL}, interrogates the operating system for the line length of the terminal device, and sets the variable {index TTYLINELENGTH Var}{var TTYLINELENGTH} to this value. If {arg N} is not {lisp NIL}, instructs the operating system to set the terminal line length to {arg N}, and also sets {var TTYLINELENGTH} to {arg N}. Then, {fn SETLINELENGTH} performs (and returns as its value) {lisp (LINELENGTH N T)}. In Interlisp-D, {fn SETLINELENGTH} merely does {lisp (LINELENGTH N T)}. }} Both {index AFTERSYSOUTFORMS Var}{var AFTERSYSOUTFORMS} and {index RESETFORMS Var}{var RESETFORMS} ({PageRef Var RESETFORMS}) contain a {lisp (SETLINELENGTH)} so that when the user first runs a {fn SYSOUT}, or types control-D{index control-D}, the system obtains the latest information about the terminal. {index *END* file attributes} }{End SubSec File Attributes} {Begin SubSec Randomly Accessible Files} {Title Randomly Accessible Files} {Text {index *BEGIN* randomly accessible files} For most applications, files are read starting at their beginning and proceeding sequentially, i.e., the next character read is the one immediately following the last character read. Similarly, files are written sequentially. However, it is also possible to read/write characters at arbitrary positions in a file, essentially treating the file as a large block of auxiliary storage. For example, one application might involve writing an expression at the {it beginning} of the file, and then reading an expression from a specified point in its {it middle}. This particular example requires the file be open for {it both} input and output. However, random file input or output can also be performed on files that have been opened for only input or only output. Associated with each file is a "file pointer"{index file pointer} that points to the location where the next character is to be read from or written to. The file pointer to a file is automatically advanced after each input or output operation. This section describes functions which can be used to {it reposition} the file pointer on those files that can be randomly accessed. A file used in this fashion is much like an array in that it has a certain number of addressable locations that characters can be put into or taken from. However, unlike arrays, files can be enlarged. For example, if the file pointer is positioned at the end of a file and anything is written, the file "grows." It is also possible to position the file pointer{index file pointer} {it beyond} the end of file and then to write. (If the program attempts to {it read} beyond the end of file, an {lisp END OF FILE}{index END OF FILE Error} error occurs.) In this case, the file is enlarged, and a "hole" is created, which can later be written into. Note that this enlargement only takes place at the {it end} of a file; it is not possible to make more room in the middle of a file. In other words, if expression {lisp A} begins at position 1000, and expression {lisp B} at 1100, and the program attempts to overwrite {lisp A} with expression {lisp C}, which is 200 characters long, part of {lisp B} will be altered. The address of a character (byte) is the number of characters (bytes) that precede it in the file, i.e., 0 is the address of the beginning of the file. However, the user should be careful about computing the space needed for an expression, since end-of-line{index end-of-line} may be represented by a different number of characters in different implementations, even though {index NCHARS FN}{fn NCHARS} only counts it as one; e.g., end-of-line in Interlisp-10 files is represented as the two characters carriage-return, line-feed. Output functions may also introduce end-of-line's as a result of {fn LINELENGTH} considerations. {note put in something about the var #EOLCHARS? No, does not exist in Interlisp-10, and use is discouraged. --bvm} {FnDef {FnName GETFILEPTR} {FnArgs FILE} {Text Returns the current position of the file pointer for {arg FILE}, i.e., the byte address at which the next input/output operation will commence. }} {FnDef {FnName SETFILEPTR} {FnArgs FILE ADR} {Text Sets the file pointer{index file pointer} for {arg FILE} to the position {arg ADR}; returns {arg ADR}. The special value {arg ADR}={lisp -1} is interpreted to mean the address of the end of file.{foot Note: If a file is opened for output only, the end of file is initially zero, even if an old file by the same name had existed (see {fn OPENFILE}, {PageRef fn OPENFILE}). If a file is opened for both input and output, the initial file pointer{index file pointer} is the beginning of the file, but {lisp (SETFILEPTR {arg FILE} -1)} will set it to the end of the file. If the file had been opened in append mode by {lisp (OPENFILE {arg FILE} 'APPEND)}, the file pointer right after opening would be set to the end of the existing file, in which case a {fn SETFILEPTR} to position the file at the end would be unnecessary. }{comment endfootnote} }} {FnDef {FnName GETEOFPTR} {FnArgs FILE} {Text Returns the byte address of the end of file, i.e., the number of bytes in the file. Equivalent to performing {lisp (SETFILEPTR {arg FILE} -1)} and returning {lisp (GETFILEPTR {arg FILE})} except that it does not change the current file pointer. }} {FnDef {FnName EOFP} {FnArgs FILE} {Text Returns {lisp T} if the file pointer to {arg FILE} is pointing to the end of file; {lisp NIL} otherwise. {arg FILE} must be open for (at least) input, or an error is generated, {lisp FILE NOT OPEN}{index FILE NOT OPEN Error}. }} {FnDef {FnName RANDACCESSP} {FnArgs FILE} {Text Returns {arg FILE} if {arg FILE} is randomly accessible, {lisp NIL} otherwise. The file {lisp T} is not randomly accessible, nor are the files {lisp LPT:}, {lisp NIL:} in Interlisp-10, or certain network file connections in Interlisp-D. {arg FILE} must be open or an error is generated, {lisp FILE NOT OPEN}{index FILE NOT OPEN Error}. }} {FnDef {FnName COPYBYTES} {FnArgs SRCFIL DSTFIL START END} {Text Copies bytes (characters) from {arg SRCFIL} to {arg DSTFIL}, starting from position {arg START} and up to but not including position {arg END}. Both {arg SRCFIL} and {arg DSTFIL} must be open. Returns {lisp T}. If {arg END}={lisp NIL}, {arg START} is interpreted as the number of bytes to copy (starting at the current position). If {arg START} is also {lisp NIL}, bytes are copied until the end of the file is reached. }} {FnDef {FnName COPYCHARS} {FnArgs SRCFIL DSTFIL START END} {Text Like {fn COPYBYTES} except that it performs the proper conversion if the {lisp EOL} conventions of {arg SRCFIL} and {arg DSTFIL} are not the same. {arg START} and {arg END} are interpreted as byte specifications in {arg SRCFIL}. The number of bytes actually output to {arg DSTFIL} might be more or less than the number of bytes specified by {arg START} and {arg END}, depending on what the {lisp EOL} conventions are. In the case where the {lisp EOL} conventions happen to be the same, {fn COPYCHARS} simply calls {fn COPYBYTES}. }} {index *BEGIN* searching files} {FnDef {FnName FILEPOS} {FnArgs PATTERN FILE START END SKIP TAIL CASEARRAY} {Text Analogous to {index STRPOS FN}{fn STRPOS} ({PageRef Fn STRPOS}), but searches a file rather than a string. {fn FILEPOS} searches {arg FILE} for the string {arg PATTERN}. Search begins at {arg START} (or the current position of the file pointer, if {arg START}={lisp NIL}), and goes to {arg END} (or the end of {arg FILE}, if {arg END}={lisp NIL}). Returns the address of the start of the match, or {lisp NIL} if not found. {arg SKIP} can be used to specify a character which matches any character in the file. If {arg TAIL} is {lisp T}, and the search is successful, the value is the address of the first character {it after} the sequence of characters corresponding to {arg PATTERN}, instead of the starting address of the sequence. In either case, the file is left so that the next i/o operation begins at the address returned as the value of {index FILEPOS FN}{fn FILEPOS}. {arg CASEARRAY} should be a "casearray" that specifies that certain characters should be transformed to other characters before matching. Casearrays are returned by {fn CASEARRAY} or {fn SEPRCASE} below. {arg CASEARRAY}={lisp NIL} means no transformation will be performed. A casearray is an implementation-dependent object that is logically an array of character codes with one entry for each possible character. {fn FILEPOS} maps each character in the file "through" {arg CASEARRAY} in the sense that each character code is transformed into the corresponding character code from {arg CASEARRAY} before matching. Thus if two characters map into the same value, they are treated as equivalent by {fn FILEPOS}. {fn CASEARRAY} and {fn SETCASEARRAY} provide an implementation-independent interface to casearrays. For example, to search without regard to upper and lower case differences, {arg CASEARRAY} would be a casearray where all characters map to themselves, except for lower case characters, whose corresponding elements would be the upper case characters. To search for a delimited atom, one could use " {arg ATOM} " as the pattern, and specify a {arg CASEARRAY} in which all of the break and separator characters mapped into the same code as space. }} For applications calling for extensive file searches, the function {fn FFILEPOS} is often faster than {fn FILEPOS}. {FnDef {FnName FFILEPOS} {FnArgs PATTERN FILE START END SKIP TAIL CASEARRAY} {Text Like {fn FILEPOS}, except much faster in most applications.{foot In Interlisp-10, a speedup of 10 to 50 times is typical. In Interlisp-D the speedup is much smaller. }{comment end footnote} {fn FFILEPOS} is an implementation of the Boyer-Moore fast string searching algorithm{index Boyer-Moore fast string searching algorithm}. This algorithm preprocesses the string being searched for and then scans through the file in steps usually equal to the length of the string. Thus, {fn FFILEPOS} speeds up roughly in proportion to the length of the string, e.g., a string of length 10 will be found twice as fast as a string of length 5 in the same position. Because of certain fixed overheads, it is generally better to use {fn FILEPOS} for short searches or short strings. }} {FnDef {Name CASEARRAY} {Args OLDARRAY} {Text Creates and returns a new casearray, with all elements set to themselves, to indicate the identity mapping. (Interlisp-D) If {arg OLDARRAY} is given, it is reused. }} {FnDef {Name SETCASEARRAY} {Args CASEARRAY FROMCODE TOCODE} {Text Modifies the casearray {arg CASEARRAY} so that character code {arg FROMCODE} is mapped to character code {arg TOCODE}. (In Interlisp-D, {fn SETCASEARRAY} is equivalent to {fn SETA}.) }} {FnDef {Name GETCASEARRAY} {Args CASEARRAY FROMCODE TOCODE} {Text Modifies the casearray {arg CASEARRAY} so that character code {arg FROMCODE} is mapped to character code {arg TOCODE}. (In Interlisp-D, {fn GETCASEARRAY} is equivalent to {fn ELT}.) }} {FnDef {FnName SEPRCASE} {FnArgs CLFLG} {Text Returns a new casearray suitable for use by {fn FILEPOS} or {fn FFILEPOS} in which all of the break/separators of {var FILERDTBL} are mapped into character code zero. If {arg CLFLG} is non-{lisp NIL}, then all CLISP characters will be mapped into this character as well. This is useful for finding a delimited atom in a file. For example, if {arg PATTERN} is {lisp " FOO "}, and {lisp (SEPRCASE T)} is used for {arg CASEARRAY}, then {fn FILEPOS} will find {lisp "(FOO_"}. }} {index *END* searching files} {index *END* Randomly Accessible Files} }{End SubSec Randomly Accessible Files} {Begin SubSec Closing and Reopening Files} {Title Closing and Reopening Files} {Text {index *BEGIN* closing and reopening files} {index *BEGIN* WHENCLOSE FN} The function {fn WHENCLOSE} permits the user to associate certain operations with open files that govern how and when the file will be closed, and how the file's status will be restored when a {fn SYSOUT} is started up. The user can specify that certain functions will be executed before {fn CLOSEF} closes the file and/or after {fn CLOSEF} closes the file. The user can make a particular file be invisible to {fn CLOSEALL}, so that it will remain open across user invocations of {fn CLOSEALL}. Finally, the user can associate a status-saving function with a file which will be called before {fn SYSOUT} and which can specify what to do when a {fn SYSOUT} is restarted. {FnDef {FnName WHENCLOSE} {FnArgs FILE PROP{SUB 1} VAL{SUB 1} {ellipsis} PROP{SUB N} VAL{SUB N}} {Type NOSPREAD} {Text {arg FILE} must specify the name of an open file other than {lisp T} ({lisp NIL} defaults to the primary input file, if other than {lisp T}, or primary output file if other than {lisp T}). The remaining arguments specify properties to be associated with the full name of {arg FILE}. {fn WHENCLOSE} returns the full name of {arg FILE} as its value. }} {fn WHENCLOSE} recognizes the following property names: {Begin LabeledList WHENCLOSE property names} {Indent 20percent} {Label {lisp BEFORE}} {Text {arg VAL} is a list of functions that {fn CLOSEF} will apply to the full name of {arg FILE} just before it is closed. This might be used, for example, to copy information about the file from an in-core data structure to the file just before it is closed. } {Label {lisp AFTER}} {Text {arg VAL} is a list of functions that {fn CLOSEF} will apply to the full name of {arg FILE} just after it is closed. This capability permits in-core data structures that know about the file to be cleaned up when the file is closed. {lisp BEFORE} and {lisp AFTER} differ in their behavior with respect to {fn SYSOUT}. If a file that was open before {fn SYSOUT} does not have a {lisp STATUS} function associated with it that causes the file to be successfully restored after the {fn SYSOUT} is started, then the file is considered to have been "closed" by the {fn SYSOUT}, and its {lisp AFTER} function will be executed after the {fn SYSOUT} starts. } {Label {lisp STATUS}} {Text This property provides a way of restoring the status of files when a {fn SYSOUT} is resumed. {arg VAL} is a function that will be applied to the full name of {arg FILE} just before a {fn SYSOUT}. {arg VAL} is expected to return a list, {fn CAR} of which is a function which will be {fn APPLY}'d to the {fn CDR} when the {fn SYSOUT} is started up and which will restore the status of {arg FILE}. If the value of the {fn APPLY} is {lisp NIL}, it is assumed the file could not be successfully restored, a warning message is printed, and then any {lisp AFTER} functions associated with the file are executed. {note need an example of this} {note STATUS may be moot for Interlisp-D, since that system already automatically tries to restore open files after logout, sysout etc.} The function {fn PERMSTATUS} ({PageRef Fn PERMSTATUS}) produces an expression for re-opening a file after {fn SYSOUT} and restoring as many of its attributes as possible. } {Label {lisp CLOSEALL}} {Text {arg VAL} is either {lisp YES} or {lisp NO} and determines whether {arg FILE} will be closed by {index CLOSEALL FN}{fn CLOSEALL} ({lisp YES}) or whether {fn CLOSEALL} will ignore it ({lisp NO}). {fn CLOSEALL} uses {fn CLOSEF}, so that any {lisp AFTER} functions will be executed if the file is in fact closed. } {Label {lisp EOF}} {Text {arg VAL} is a function that will be applied to the full name of {arg FILE} when an end-of-file error occurs, and the {var ERRORTYPELST} entry for that error, if any, returns {lisp NIL}. The function can examine the context of the error, and can decide whether to close the file, {fn RETFROM} some function, or perform some other computation. If the function supplied returns normally (i.e. does not {fn RETFROM} some function), the normal error machinery will be invoked (but {arg FILE} will not be automatically closed if the {lisp EOF} function did not close it). {Note there should be a more elegent way to have no error other than using a RETFROM. Perhaps if the EOF fn returns non-NIL, there should be no error.} {Note What is the relationship between this and the EndOfStreamError slot in an Interlisp-D stream?} } {End LabeledList WHENCLOSE property names} Note that multiple {lisp AFTER} and {lisp BEFORE} functions may be associated with a file; they are executed in sequence with the most recently associated function executed first. However, a second {lisp STATUS} specification will supercede an earlier one. The {lisp CLOSEALL} and {lisp EOF} values will also override earlier values, so only the last value specified will have an effect. Files are initialized with {lisp CLOSEALL} - {lisp YES}, {lisp EOF} - {lisp CLOSEF}. {index *END* closing and reopening files} {index *END* WHENCLOSE FN} }{End SubSec Closing and Reopening Files} {Begin SubSec Dribble Files} {Title Dribble Files} {Text {note {fn DRIBBLE} was written by D. C. Lewis.} {Tag DribbleFiles} A dribble file is a "transcript" of all of the input and output on a terminal. The following function enables dribble files for Interlisp: {FnDef {FnName DRIBBLE} {FnArgs FILENAME APPENDFLG THAWEDFLG} {Text Opens {arg FILENAME} and begins recording the typescript. Returns the old dribble file if any, otherwise {lisp NIL}. If {arg APPENDFLG}={lisp T}, the typescript will be appended to the end of {arg FILENAME}. If {arg THAWEDFLG}={lisp T}, the file will be opened in "thawed" mode, for those implementations that support it. {lisp (DRIBBLE)} closes the dribble file. Only one dribble file can be active at any one time, so {lisp (DRIBBLE {arg FILE1})} followed by {lisp (DRIBBLE {arg FILE2})} will cause {arg FILE1} to be closed. In Interlisp-D, {fn DRIBBLE} opens a dribble file for the current process, recording the input and output for that process. Multiple processes can have separate dribble files open at the same time. }} {FnDef {FnName DRIBBLEFILE} {FnArgs} {Text Returns the name of the current dribble file, if any, otherwise {lisp NIL}. }} Terminal input is echoed to the dribble file a line buffer at a time. Thus, the typescript produced is somewhat neater than that appearing on the user's terminal, because it does {it not} show characters that were erased via control-A or control-Q. Note that the typescript file is {it not} included in the list of files returned by {lisp (OPENP)}, nor will it be closed by a call to {fn CLOSEALL} or {fn CLOSEF}. Only {lisp (DRIBBLE)} closes the typescript file. }{End SubSec Dribble Files} {index *END* files} }{End SubSec Files} {£GACHA c TIMESROMAN GACHA  TIMESROMAN GACHA  TIMESROMAN GACHA  TIMESROMAN GACHA + TIMESROMAN GACHA * TIMESROMAN GACHA = TIMESROMAN GACHA  TIMESROMAN GACHA ¥ TIMESROMAN -?GACHA ª÷z¸