SECTION 14 INPUT/OUTPUT FUNCTIONS 14.1 FILES All input/output functions in INTERLISP can specify their source/destination file with an optional extra argument which is the name of the file. This file must be opened as specified below. If the extra argument is not given (has value NIL), the file specified as "primary" for input (output) is used. Normally these are both T, for terminal input and output. However, the primary input/output file may be changed by 1 input[file] Sets file as the primary input file. Its value is the name of the old primary input file. input[] returns current primary input file, which is not changed. output[file] Same as input except operates on primary output file. Any file which is made primary must have been previously opened for input/output, except for the file T, which is always open. infile[file] Opens file for input, and sets it as the primary 2 input file. The value of infile is the previous primary input file. If file is already open, same as input[file]. Generates a FILE WON'T OPEN error if file won't open, e.g., file is already open for output. ------------------------------------------------------------------------ 1 The argument name file is used for tutorial purposes only. Subrs do not have argument "names", per se, as described in Section 8. 2 To open file without changing the primary input file, perform input[infile[file]]. 14.1 outfile[file] Opens file for output, and sets it as the 3 primary output file. The value of outfile is the previous primary output file. If file is already open, same as output[file]. Generates a FILE WON'T OPEN error if file won't open, e.g., if file is already open for input. In INTERLISP-10, for all input/output functions, file follows the TENEX conventions for file names, i.e., file can be prefixed by a directory name enclosed in angle brackets, can contain alt-modes or control-F's, and can include suffixes and/or version numbers. Consistent with TENEX, when a file is opened for input and no version number is given, the highest 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. In INTERLISP-10, regardless of the file name given to the INTERLISP function that opened the file, INTERLISP maintains only full TENEX file 4 names in its internal table of open files and any function whose value is a file name always returns a full file name, e.g., openp[FOO]=FOO.;3. Whenever a file argument is given to an i/o function, INTERLISP first checks to see if the file is in its internal table. If not, INTERLISP executes the appropriate TENEX JSYS to "recognize" the file. If TENEX does not successfully recognize the 5 file, a FILE NOT FOUND error is generated. If TENEX does recognize the file, it returns to INTERLISP the full file name. Then, INTERLISP can continue with the indicated operation. If the file is being opened, INTERLISP opens the file and stores its (full) name in the file table. If it is being closed, or written to or read from, INTERLISP checks its internal table to make sure the file is open, and then executes the corresponding operation. Note that each time a full file name is not used, INTERLISP-10 must call TENEX to recognize the name. Thus if repeated operations are to be performed, it is considerably more efficient to obtain the full file name once, e.g., via infilep or outfilep. Also, note that recognition by TENEX is performed on the user's entire directory. Thus, even if only one file is open, say FOO.;1, F$ (F altmode) will not be recognized if the user's directory also contains the file FIE.;1. Similarly, it is ------------------------------------------------------------------------ 3 To open file without changing the primary output file, perform output[outfile[file]]. 4 i.e., directory name, extension, and version. 5 except for infilep, outfilep and openp, which in this case return NIL. 14.2 possible for a file name that was previously recognized to become ambiguous. For example, a program performs infile[FOO], opening FOO.;1, and reads several expressions from FOO. Then the user types control-C, creates a FOO.;2 and reenters his program. Now a call to read giving it FOO as its file argument will generate a FILE NOT OPEN error, because TENEX will recognize FOO as FOO.;2. infilep[file] Returns full file name of file if file is recognized as specifying the name of a file that can be opened for input, NIL otherwise. In INTERLISP-10, the full file name will contain a directory field only if the directory differs from the currently attached directory. Recognition is in input context, i.e., in INTERLISP-10, if no version number is given, the highest version number is returned. infilep and outfilep do not open any files, or change the primary files; they are pure predicates. outfilep[file] Similar to 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 version number is returned. closef[file] Closes file. Generates an error, FILE NOT OPEN, if file not open. If file is NIL, it attempts to close the primary input file if other than terminal. Failing that, it attempts to close the primary output file if other than terminal. Failing both, it returns 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. closeall[] Closes all open files (except T and the current typescript file, if any). Value is a list of the files closed. openp[file;type] If type=NIL, value is file (full name) if file is open either for reading or for writing. Otherwise value is NIL. If type is INPUT or OUTPUT, value is file if open for corresponding type, otherwise NIL. If type is BOTH, value is file if open for both input and output, (See iofile, page 14.5) otherwise NIL. Note: the value of openp is NIL if file is not recognized, i.e., openp does not generate an error. 14.3 openp[] returns a list of all files open for input or output, excluding T and the current typescript file, if any. delfile[file] deletes file if possible. Value is file if deleted, else NIL. renamefile[old;new] renames old to be new. Value is new if successful, else NIL. ADDRESSABLE 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. A program need not be aware of the fact that there is a file pointer associated with each file that points to the location where the next character is to be read from or written to, and that this file pointer is automatically advanced after each input or output operation. This section describes a function which can be used to reposition the file pointer, thereby allowing a program to treat a file as a large block of auxiliary storage which can be accessed 6 randomly. For example, one application might involve writing an expression at the beginning of the file, and then reading an expression 7 from a specified point in its middle. 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 8 the file pointer beyond the end of file and then to write. In this case, the file is enlarged, and a "hole" is created, which can later be ------------------------------------------------------------------------ 6 Random access means that any location is as quickly accessible as any other. For example, an array is randomly accessible, but a list is not, since in order to get to the nth element you have to sequence through the first n-1 elements. 7 This particular example requires the file be open for both input and output. This can be achieved via the function iofile described below. However, random file input or output can be performed on files that have been opened in the usual way by infile or outfile. 8 If the program attempts to read beyond the end of file, an END OF FILE error occurs. 14.4 written into. Note that this enlargement only takes place at the end of a file; it is not possible to make more room in the middle of a file. In other words, if expression A begins at positon 1000, and expression B at 1100, and the program attempts to overwrite A with expression C, which is 200 characters long, part of B will be clobbered. iofile[file] Opens file for both input and output. Value is file. Does not change either primary input or primary output. If no version number is given, default is same as for infile, i.e., highest version number. getfileptr[file] returns current value of file pointer for file, i.e., the byte address at which the next input/output operation will commence. 9 setfileptr[file;adr] sets file pointer for file to adr. Value is 10 adr. adr=-1 corresponds to the end of file. geteofptr[file] Value is byte address of end of file, i.e., the number of bytes in the file. Equivalent to performing setfileptr[file;-1] and returning getfileptr[file] except does not change the current file pointer. ------------------------------------------------------------------------ 9 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 in INTERLISP-10 is represented as two characters in a file, but nchars only counts it as one. 10 Note: in INTERLISP-10, if a file is opened for output only, either by outfile, or openf[file;100000q] (see page 14.7), TENEX assumes that one intends to write a new or different file, even if a version number was specified and the corresponding file already exists. Thus, setfileptr[file;-1] will set the file pointer to 0. If a file is opened for both reading and writing, either by iofile or openf[file;300000q], TENEX assumes that there might be material on the file that the user intends to read. Thus, the initial file pointer is the beginning of the file, but setfileptr[file;-1] will set it to the end of the file. Note that one can also open a file for appending by openf[file;20000q]. In this case, the file pointer right after opening is set to the end of the existing file. Thus, a write will automatically add material at the end of the file, and an setfileptr is unnecessary. 14.5 11 filepos[x;file;start;end;skip;tail] Searches file for x a la strpos (Section 10). Search begins at start (or if start=NIL, the current position of file pointer), and goes to end (or if end=NIL, to the end of file). Value is address of start of match, or NIL if not found. skip can be used to specify a character which matches any character in the file. If tail is T, and the search is successful, the value is the address of the first character after the sequence of characters corresponding to x, 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 filepos. For applications calling for extensive file searches, the function ffilepos (below) will generally be 10 to 50 times faster than filepos. ffilepos is an implementation of the Boyer-Moore fast string searching algorithm [Boy]. 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, 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 filepos for searches through fewer than 100 characters of the file. For longer searches, ffilepos will generally be marginally faster for short strings (length 3 or less) and significantly faster for longer strings. 12 ffilepos[x;file;start;end;unused;tail] Like filepos, except much faster in most appliations. There are two restrictions. The skip character option of filepos is not available even though such an argument position is supplied for compatibility with filepos. If a skip character is supplied it is ignored. The second restriction is that x may not contain more than 95 characters. This restriction is due to the fixed size of certain tables set up during the preprocessing. copybytes[srcfil;dstfil;start;end] copies bytes, i.e., characters, from srcfil to ------------------------------------------------------------------------ 11 filepos was written by J. W. Goodwin. 12 ffilepos was written by J Strother Moore. 14.6 dstfil starting from position start and up to but not including position end. Both srcfil and dstfil must be open. Value is T. OPENF The following function is available in INTERLISP-10 for specialized file applications: openf[file;x] opens file. x is a number whose bits specify the access and mode for file, i.e., x corresponds to the second argument to the TENEX JSYS OPENF (see JSYS Manual). Value is full name of file. openf permits opening a file for read, write, execute, or append, etc. and allows specification of byte size, i.e., a byte size of 36 enables reading and writing of full words. openf does not affect the primary input or output file settings, and does not check whether the file is already open - i.e., the same file can be opened more than once, 13 possibly for different purposes. openp will work for files opened with openf. The first argument to openf can also be a number, which is then interpreted as JFN. This results in a more efficient call to openf, and can be signficant if the user is making frequent calls to openf, e.g., switching byte sizes. 14 THE JFN FUNCTIONS IN INTERLISP-10 JFN stands for job file number. It is an integral part of the TENEX file system and is described in [Mur1], and in somewhat more detail in the TENEX JSYS manual. In INTERLISP-10, the following functions are available for direct manipulation of JFNs: opnjfn[file] returns the JFN for file. If file not open, generates a FILE NOT OPEN error. ------------------------------------------------------------------------ 13 The "thawed" bit in x permits opening a file that is already open. 14 THE JFN FUNCTIONS WERE WRITTEN BY J. W. GOODWIN. 14.7 Example: to write a byte on a file [DEFINEQ (BOUT (LAMBDA (FILE BYTE) (LOC (ASSEMBLE NIL (CQ (VAG BYTE)) (PUSH NP , 1) (CQ (VAG (OPNJFN FILE))) (POP NP , 2) (JSYS 51Q) (MOVE 1 , 2)] or to read a byte from a file [DEFINEQ (BIN (LAMBDA (FILE) (LOC (ASSEMBLE NIL (CQ (VAG (OPNJFN FILE))) (JSYS 50Q) (MOVE 1 , 2] Making BIN and BOUT substitution macros can save boxing and unboxing in compiled code. gtjfn[file;ext;v;flags] sets up a "long" call to GTJFN (see JSYS manual). file is a file name possibly containing control-F and/or alt-mode. ext is the default extension, v the default version (overriden if file specifies extension/version, e.g., FOO.COM;2). flags is as described on page 17, section 2 of JSYS manual. file and ext may be strings or atoms; v and flags must be numbers. Value is JFN, or NIL on errors. rljfn[jfn] releases jfn. rljfn[-1] releases all JFN's which do not specify open files. Value of rljfn is T. jfns[jfn;ac3] converts jfn (a small number) to a file name. ac3 is either NIL, meaning format the file name as would openp or other INTERLISP-10 file functions, or else is a number, meaning format according to JSYS manual. The value of jfns is atomic except where enough options are specified by ac3 to exceed atom size (> 100 characters). In this case, the value is returned as a string. 14.8 14.2 INPUT FUNCTIONS Most of the functions described below have an (optional) argument file which specifies the name of the file on which the operation is to take place, and an (optional) argument rdtbl, which specifies the readtable to be used for input. If file is NIL, the primary input file will be used. If the file argument is a string, input will be taken from that string (and the string pointer reset accordingly). If rdtbl is NIL, the primary readtable will be used. readtables are described on page 14.17. Note: in all INTERLISP-10 symbolic files, end-of-line is indicated by the characters carriage-return and line-feed in that order. Accordingly, on input from files, INTERLISP-10 will skip all line-feeds which immediately follow carriage-returns. On input from terminal, INTERLISP will echo a line-feed whenever a carriage-return is input. For all input functions except readc and peekc, when reading from the terminal, control-A erases the last character typed in, echoing a \ and the erased character. Control-A will not backup beyond the last carriage-return. Typing control-Q causes INTERLISP to print ## and clear the input buffer, i.e., erase the entire line back to the last 15 carriage-return. When reading from a file, and an end of file is encountered, all input functions close the file and generate an error, END OF FILE. read[file;rdtbl;flg] Reads one S-expression from file. Atoms are delimited by the break and separator characters as defined in rdtbl. To input an atom which contains a break or separator character, precede the character by the escape character %, e.g., AB%(C, is the atom AB(C, %% is the atom %, %^A (i.e., %control-A) is the atom ^A. For input from the terminal, an atom containing an interrupt character can be input by typing instead the corresponding alphabetic character preceded by control-V, e.g., ^VC for control-C. Strings are delimited by double quotes. To input a string containing a double quote or a %, precede it by %, e.g., "AB%"C" is the string AB"C. Note that % can always be typed even if next character is not "special", e.g., %A%B%C is read as ABC. If an atom is interpretable as a number, read will create a number, e.g., 1E3 reads as a floating point number, 1D3 as a literal atom, ------------------------------------------------------------------------ 15 Note that the CHARDELETE and LINEDELETE characters can be redefined or disabled via setsyntax, see page 14.19. 14.9 1.0 as a number, 1,0 as a literal atom, etc. Note that an integer can be input in octal by terminating it with a Q, e.g., 17Q and 15 read in as the same integer. The setting of radix, page 14.30, determines how integers are printed, i.e., with or without Q's. When reading from the terminal, all input is line-buffered to enable the 16 action of control-Q. Thus no characters are actually seen by the 17 program until a carriage-return is typed. However, for reading by read, when a matching right parenthesis is encountered, the effect is the same as though a carriage-return were typed, i.e., the characters 18 are transmitted. To indicate this, INTERLISP also prints a carriage-return line-feed on the terminal. flg=T suppresses the carriage-return normally typed by read following a matching right parenthesis. (However, the characters are still given to read - i.e., the user does not have to type the carriage-return himself.) When reading a list, typing control-W erases the last expression read, echoing a \\ and the erased expression, e.g., (NOW IS THE TIME^W \\ TIME) returns (NOW IS THE). Control-W can be used repeatedly, and can also back up and erase 19 expressions on previous lines. ratom[file;rdtbl] Reads in one atom from file. Separation of atoms is defined by rdtbl. % is also an escape ------------------------------------------------------------------------ 16 Unless control[T] has been performed (page 14.28). 17 Actually, the line buffering is terminated by the character with terminal syntax class EOL (see page 14.25), which in most cases will be carriage-return. 18 The line buffer is also transmitted to read whenever an IMMEDIATE read-macro character is typed (see page 14.22). 19 However, since control-W is implemented as an IMMEDIATE read-macro character, (see page 14.22), once it is typed, characters typed before it cannot be deleted by control-A or control-Q, since they will already have passed through the line buffer. 14.10 character for ratom, and the remarks concerning control-A, control-Q, control-V, and line-buffering also apply. If the characters comprising the atom would normally be interpreted as a number by read, that number is also returned by ratom. Note however that ratom takes no special action for " whether or not it is a break character, i.e., ratom never makes a string. rstring[file;rdtbl] Reads in one string from file, terminated by next break or separator character. Control-A, control-Q, control-V, and % have the same effect as with ratom. Note that the break or separator character that terminates a call to ratom or rstring is not read by that call, but remains in the buffer to become the first character seen by the next reading function that is called. ratoms[a;file;rdtbl] Calls ratom repeatedly until the atom a is read. Returns a list of atoms read, not including a. setsepr[lst;flg;rdtbl] Set separator characters for rdtbl. Value is NIL. setbrk[lst;flg;rdtbl] Set break characters for rdtbl. Value is NIL. 20 For both setsepr and setbrk, lst is a list of character codes, flg determines the action of setsepr/setbrk as follows: NIL clear out indicated readtable and reset break/separator characters to be those in lst. 0 clear out only those characters in lst - i.e., this provides an unsetsepr and unsetbrk. 1 add characters in lst. Characters specified by setbrk will delimit atoms, and be returned as separate atoms themselves by ratom. Characters specified by setsepr ------------------------------------------------------------------------ 20 If lst=T, the break/separator characters are reset to be those in the system's readtable for terminals, regardless of value of flg, i.e., setbrk[T] is equivalent to setbrk[getbrk[T]]. If rdtbl is T, then the characters are reset to those in the original system table. 14.11 will serve only to delimit atoms, and are otherwise ignored. For example, if $ was a break character and * a separator character, the input stream ABC**DEF$GH*$$ would be read by 6 calls to ratom returning respectively ABC, DEF, $, GH, $, $. The elements of lst may also be characters, e.g., setbrk[(. ,)] has the same effect in INTERLISP-10 as setbrk[(46 44)]. Note however that the "characters" 1,2,...,9 will be interpreted as character codes because they are numbers. Note: (, ), [, ], and " are normally break characters, i.e., will be returned as separate atoms when read by ratom. If any of these break characters are disabled by an appropriate setbrk (or by making it be a separator character), its special action for read will not be restored 21 by simply making it be a break character again with setbrk. For more details, see discussion in section on readtables, page 14.20-20. Note that the action of % is not affected by setsepr or setbrk. To defeat the action of % use escape[], as described below. getsepr[rdtbl] Value is a list of separator character codes. getbrk[rdtbl] Value is a list of break character codes. escape[flg] If flg=NIL, makes % act like every other 22 character for input. Normal setting is escape[T]. The value of escape is the previous setting. ratest[x] If x = T, ratest returns T if a separator was encountered immediately prior to the last atom read by ratom, NIL otherwise. If x = NIL, ratest returns T if last atom read by ratom or read was a break character, NIL otherwise. If x = 1, ratest returns T if last atom read (by read or ratom) contained a % (as an escape character, e.g., %[ or %A%B%C), NIL otherwise. ------------------------------------------------------------------------ 21 However, making these characters be break characters when they already are will have no effect. 22 escape does not currently take a readtable argument, but will probably do so in the near future. 14.12 readc[file] Reads the next character, including %, ", etc, i.e., is not affected by break, separator, or escape character. Value is the character. Action of readc is subject to line-buffering, i.e., readc will not return a value until the line has been terminated even if a character has been typed. Thus, control-A, control-Q, and control-V will have their usual effect. If control[T] has been executed (page 14.28), defeating line-buffering, readc will return a value as soon as a character is typed. In addition, if control-A, control-Q, or control-V are typed, readc will return them as values. peekc[file;flg] Value is the next character, but does not actually read it, i.e., remove it from the buffer. If flg=NIL, peekc is not subject to line-buffering, i.e., it returns a value as soon as a character has been typed. If flg=T, peekc waits until the line has been terminated before returning its value. This means that control-A, control-Q, and control-V will be able to perform their usual editing functions. lastc[file] Value is last character read from file. Note: read, ratom, ratoms, peekc, readc all wait for input if there is none. The only way to test whether or not there is input is to use readp. readp[file;flg] Value is T if there is anything in the input 23 buffer of file, NIL otherwise. Note that because of line-buffering, readp may return T, indicating there is input in the buffer, but read may still have to wait. 24 readline[rdtbl] reads a line from the terminal, returning it as ------------------------------------------------------------------------ 23 Frequently, the input buffer will contain a single EOL character left over from a previous input. For most applications, this situation wants to be treated as though the buffer were empty, and so readp returns NIL. However, if flg=T, readp will also return T in this case, i.e., will return T if there is any character in the input buffer. 24 Readline actually has two extra arguments for use by the system, but the user should consider it as a function of one argument. 14.13 a list. If readp[T] is NIL, readline returns NIL. Otherwise it reads expressions, using 25 read, until it encounters either: (1) a carriage-return (typed by the user) that is not preceded by any spaces, e.g., A B CC 26 and readline returns (A B C) (2) a list terminating in a "]", in which case the list is included in the value of readline, e.g., A B (C D] and readline returns (A B (C D)). (3) an unmatched right parentheses or right square bracket, which is not included in the value of readline, e.g., A B C] and readline returns (A B C). In the case that one or more spaces precede a carriage-return, or a list is terminated with a ")", readline will type "..." and continue reading 27 on the next line, e.g., A B C C ...(D E F) ...(X Y Z] and readline returns (A B C (D E F) (X Y Z)). ------------------------------------------------------------------------ 25 Actually, readline performs (APPLY* LISPXREADFN T), as described in Section 22. lispxreadfn is initially READ. 26 Note that carriage-return, i.e., the EOL character, can be redefined with setsyntax, page 14.19. readline actually checks for the EOL character, whatever that may be. The same is true for right parenthesis and right bracket. 27 If the user then types another carriage-return, the line will terminate, e.g., A B C C ...C and readline returns (A B C). 14.14 28 skread[file;rereadstring] is a skip read function. It moves the file pointer for file ahead as if one call to read had been performed, without paying the storage and compute cost to really read in the structure. rereadstring is for the case where the user has already performed some readc's and ratom's before deciding to skip this expression. In this case, rereadstring should be the material already read (as a string), and skread operates as though it had seen that material first, thus getting its paren-count, double-quote count, etc. set up properly. The value of skread is %) if the first thing encountered was a closing paren; %] if the read terminated on an unbalanced %], i.e., one which also would have closed any extant open left parens; otherwise the value of skread is NIL. 14.3 OUTPUT FUNCTIONS Most of the functions described below have an (optional) argument file which specifies the name of the file on which the operation is to take place. If file is NIL, the primary output file will be used. Some of the functions have an (optional) argument rdtbl, which specifies the readtable to be used for output. If rdtbl is NIL, the primary readtable will be used. Note: in all INTERLISP-10 symbolic files, end-of-line is indicated by the characters carriage-return and line-feed in that order. Unless otherwise stated, carriage-return appearing in the description of an output function means carriage-return and line-feed. prin1[x;file] prints x on file. prin2[x;file;rdtbl] prints x on file with %'s and "'s inserted where required for it to read back in properly by read, using rdtbl. Both prin1 and prin2 print lists as well as atoms and strings; prin1 is usually used only for explicitly printing formatting characters, e.g., (PRIN1 (QUOTE %[)) might be used to print a left square bracket (the % would not be printed by prin1). prin2 is used for printing S-expressions which can then be read back into INTERLISP with read i.e., break and separator characters in atoms will be preceded by %'s, e.g., ------------------------------------------------------------------------ 28 skread was written by J. W. Goodwin. It always uses filerdtbl for its readtable. 14.15 the atom "()" is printed as %(%) by prin2. If radix=8, prin2 prints a Q after integers but prin1 does not (but both print the integer in octal). print[x;file;rdtbl] Prints the S-expression x using prin2; followed by a carriage-return line-feed. Its value is x. For all printing functions, pointers other than lists, strings, atoms, or numbers, are printed as #N, where N is the octal representation of the address of the pointer (regardless of radix). Note that this will not read back in correctly, i.e., it will read in as the atom "#N". spaces[n;file] Prints n spaces; its value is NIL. terpri[file] Prints a carriage-return; its value is NIL. PRINTLEVEL The print functions print, prin1, and prin2 are all affected by a level parameter set by: printlevel[n] Sets print level to n, value is old setting. Initial value is 1000. printlevel[] gives current setting. The variable n controls the number of unpaired left parentheses which will be printed. Below that level, all lists will be printed as &. Suppose x = (A (B C (D (E F) G) H) K). Then if n = 2, print[x] would print (A (B C & H) K), and if n = 3, (A (B C (D & G) H) K), and if n = 0, just &. If printlevel is negative, the action is similar except that a carriage-return is inserted between all occurrences of right parenthesis immediately followed by a left parenthesis. The printlevel setting can be changed dynamically, even while INTERLISP is printing, by typing control-P followed by a number, i.e., a string of 29 digits, followed by a period or exclamation point. The printlevel will ------------------------------------------------------------------------ 29 As soon as control-P is typed, INTERLISP clears and saves the input buffer, clears the output buffer, rings the bell indicating it has seen the control-P, and then waits for input which is terminated by any non-number. The input buffer is then restored and the program continues. If the input was terminated by other than a period or an exclamation point, it is ignored and printing will continue, except that characters cleared from the output buffer will have been lost. 14.16 30 immediately be set to this number. If the print routine is currently deeper than the new level, all unfinished lists above that level will be terminated by "--)". Thus, if a circular or long list of atoms, is being printed out, typing control-P0. will cause the list to be terminated. If a period is used to terminate the printlevel setting, the printlevel will be returned to its previous setting after this printout. If an exclamation point is used, the change is permanent and the printlevel is not restored (until it is changed again). Note: printlevel only affects terminal output. Output to all other files acts as though level is infinite. 31 14.4 READTABLES AND TERMINAL TABLES The INTERLISP input and (to a certain extent) output routines are table 32 driven by readtables and terminal tables. A readtable is a datum that contains information about the syntax class of each character, e.g., break character, separator character, escape character, list or string delimiter, etc. The system packages use three readtables: T for input/output from terminals, (the value of) filerdtbl for input/output from files, and (the value of) editrdtbl, for input from terminals while in the editor. These three tables are initially equal but not eq. Using the functions described below, the user may change, reset, or copy these tables. He can also create his own readtables, and either explicitly pass them to input/output functions as arguments, or install them as the primary readtable, via setreadtable, and then not specify a rdtbl argument, i.e., use NIL. In the discussion below, most functions that accept readtable arguments will also accept NIL as indicating the primary readtable, or T as indicating the system's readtable for terminals. Where indicated, some will also accept ORIG (not the value of ORIG) as indicating the original system readtable. ------------------------------------------------------------------------ 30 Another way of "turning off" output is to type control-O, which simply clears the output buffer, thereby effectively skipping the next (up to) 64 characters. 31 READTABLES AND TERMINAL TABLES WERE DESIGNED AND IMPLEMENTED BY D. C. LEWIS. 32 In INTERLISP-10, readtables are represented (currently) by 128 word arrays. 14.17 READTABLE FUNCTIONS readtablep[rdtbl] Value is rdtbl, if rdtbl is a real readtable, otherwise NIL. getreadtable[rdtbl] If rdtbl=NIL, value is primary read table. If rdtbl=T, value is system's readtable for terminals. If rdtbl is a real readtable, value is rdtbl. Otherwise, generates an ILLEGAL READTABLE error. 33 setreadtable[rdtbl;flg] resets primary readtable to be rdtbl. Generates ILLEGAL READTABLE error if rdtbl is not NIL, T, or a real readtable. Value is previous setting of primary readtable, i.e., setreadtable is suitable for use with resetform (Section 5). copyreadtable[rdtbl] value is a copy of rdtbl. rdtbl can be a real readtable, NIL, T, or ORIG, in which case value is a copy of original system readtable, otherwise generates an ILLEGAL READTABLE error. Note that copyreadtable is the only function that creates a readtable. resetreadtable[rdtbl;from] copies (smashes) from into rdtbl. from and rdtbl can be NIL, T, or a real readtable. In addition, from can be ORIG, meaning use system's original readtable. SYNTAX CLASSES A syntax class is a group of characters which behave the same with respect to a particular input/output operation. For example, break characters belong to the syntax class BREAK, separators belong to the class SEPR, [ belongs to the class LEFTBRACKET, " to STRINGDELIM, etc. 34 Characters that are not otherwise special belong to the class OTHER. ------------------------------------------------------------------------ 33 If flg=T, setreadtable resets the system readtable for terminals. Note that the user can reset the other system readtables with setq, e.g., (SETQ FILERDTBL (GETREADTABLE)). 34 There are currently 11 syntax classes for readtables: LEFTBRACKET, RIGHTBRACKET, LEFTPAREN, RIGHTPAREN, STRINGDELIM, ESCAPE, BREAK, SEPR, BREAKCHAR, SEPRCHAR, and OTHER. Syntax classes for terminal tables are discussed on page 14.25. 14.18 The functions below are used to obtain and (re)set the syntax class of a character. ch can either be a character code, or a character, i.e., if ch is a number, it is interpreted as a character code. For example, in INTERLISP-10, 1 indicates control-A, and 49 indicates the character 1. getsyntax[ch;table] Value is syntax class of ch with respect to table. table can be NIL, T, ORIG, or a real readtable or terminal table. ch is either a character code, a character, or a syntax class. In the last case, the value of getsyntax is a list of the character codes in that class, e.g., getsyntax[BREAK]=getbrk[]. setsyntax[ch;class;table] sets syntax class of ch, a character code, or a character. table can be either NIL, T, or a real readtable or terminal table. class is a syntax class, or in the case of read-macro characters (page 14.20), an expression of the form (type ... options ... fn). The value of setsyntax is the previous class of ch. setsyntax will also accept class=NIL, T, ORIG, or a real readtable or terminal table, as being equivalent to getsyntax[ch;class], i.e., means give ch the syntax class it has in the table indicated by class, e.g., setsyntax[%(;ORIG]. class can also be a character code or character, which is equivalent to getsyntax[class;table], i.e., means give ch the syntax class of the character indicated by class, e.g., setsyntax[{;%[]. syntaxp[code;class;table] table is NIL, T, or a real readtable or terminal table. Value is T if code is a member of syntax class class, e.g., syntaxp[40;LEFTPAREN]=T. syntaxp compiles open. Note that syntaxp will not accept a character as an argument. FORMAT CHARACTERS A format character is a character which is recognized as special by read. There are six format characters in INTERLISP namely [, ], (, ), ", and %. The six corresponding syntax classes are: LEFTBRACKET, RIGHTBRACKET, LEFTPAREN, RIGHTPAREN, STRINGDELIM, and ESCAPE. (Note that the class ESCAPE refers to the input escape character.) Making a character be a format character does not disable the character currently filling that function, i.e., it is perfectly acceptable to have both { and [ function as left brackets. To disable a format character, assign it syntax class OTHER, e.g., setsyntax[%";OTHER]. 14.19 BREAKS, SEPARATORS, AND READTABLES The syntax class BREAK (or SEPR) corresponds to those characters treated as break (or separator) characters by ratom. Thus, getsyntax[BREAK;rdtbl] is equivalent to getbrk[rdtbl], and setsyntax[ch;BREAK;rdtbl] is equivalent to setbrk[list[ch];1;rdtbl]. Note that the characters corresponding to the syntax classes LEFTBRACKET, RIGHTBRACKET, LEFTPAREN, RIGHTPAREN, and STRINGDELIM are all break characters, and therefore members of the class BREAK. However, getsyntax applied to these characters will return the syntax class corresponding to their format character function, not BREAK. In fact, getsyntax will never return BREAK or SEPR as a value. Instead, characters which are break or separator characters but have no other special function belong to the syntax class BREAKCHAR or SEPRCHAR (as well as being members of the class BREAK or SEPR). In most cases, BREAK can be used interchangeably with BREAKCHAR. However, note that setsyntax[%(;BREAK] is a nop (since %( is already a break character), but that setsyntax[%(;BREAKCHAR] means make %( be just a break character, and therefore disables the LEFTPAREN function of %(. It is equivalent to setsyntax[%(;OTHER] followed by setsyntax[%(;BREAK]. If the user does disable one of the format characters, e.g., by performing setsyntax[%(;OTHER], it is not sufficient for restoring the formatting function simply to make the character again into a break character, i.e., setsyntax[%(;BREAK] would not restore %( as LEFTPAREN. READ MACRO CHARACTERS The user can define various characters as read-macro characters by specifying as a class an expression of the form (type fn), where type is MACRO, SPLICE, or INFIX, and fn is the name of a function, or a lambda expression. Whenever read encounters a read-macro character, it calls the associated function, giving it as arguments the input file and readtable being used for that call to read. The interpretation of the value returned depends on the type of read-macro: (1) MACRO The result is inserted into the input as if that expression had been read, instead of the read-macro character. For example, ' could be defined by: 35 [MACRO(LAMBDA(FL RDTBL)(KWOTE(READ FL RDTBL]. (2) SPLICE The result (which should be a list or NIL) is nconc'ed into the input list, e.g., if ! is defined by (SPLICE (LAMBDA NIL (APPEND FOO))), and the value of foo is (A B C), when the user inputs (X ! Y), the result will be (X A B C Y). ------------------------------------------------------------------------ 35 ' is standardly defined as a read-macro character. The actual definition checks to see if the next character is a separator, right paren, or right bracket, and if so returns ' itself, e.g., (A ' B) is read as (A ' B). 14.20 (3) INFIX The associated function is called with the list of what has been read (current level list only), 36 in tconc format, as its third argument. The function's value is taken as a new tconc list which replaces the old one. For example, + could be defined by: (INFIX (LAMBDA (FL RDTBL Z) (RPLACA (CDR Z) (LIST (QUOTE IPLUS) (CADR Z) (READ FL RDTBL))) Z)) The specification for a read-macro character can be augmented to specify various options by giving setsyntax a list of the form (type ... options ... fn), e.g., (MACRO FIRST IMMEDIATE fn), with the following interpretations: ALWAYS the read-macro character is a break character, and is always effective (except when preceded by the escape character). FIRST the read-macro character is not a break 37 character, and is interpreted as a read-macro character only when it is the first character seen after a break or separator character, e.g., ' is a FIRST read-macro character, so that A'B is read as A'B. ALONE the read-macro character is not a break character, and is interpreted as a read-macro character only when the character would have been read as a separate atom if it were not a read-macro character, i.e., when its immediate ------------------------------------------------------------------------ 36 If an INFIX read-macro character is encountered not in a list, the third argument to its associated function will be NIL. If the function returns NIL, the read-macro character is essentially ignored and reading continues. Otherwise, if the function returns a tconc list of one element, that element is the value of the read. If it returns a tconc list of more than one element, the list is the value of the read. 37 Making a FIRST or ALONE read-macro character be a break character disables the read-macro interpretation, i.e., converts it to syntax class BREAKCHAR. Making an ALWAYS read-macro character be a break character is a NOP. 14.21 neighbors are both break or separator characters, e.g., * is an ALONE read-macro character in order to implement the comment map feature (see page 14.48). Note: ALWAYS is the default option for ALWAYS, FIRST, and ALONE. ESCQUOTE, ESC when printed with prin2, the read-macro character will be preceded by the escape character. NOESCQUOTE, NOESC the read-macro character will be printed without an escape, e.g., ' is a NOESCQUOTE character. ESCQUOTE is the default option for ESCQUOTE and NOESCQUOTE. IMMEDIATE, IMMED the read-macro character is immediately activated, i.e., the character is essentially seen by the line buffer, as an EOL, and the rest 38 of the line is passed to the input function. 39 IMMEDIATE read-macro characters enable the user to specify a character that will take 40 effect immediately. For example, control-W is defined as an IMMEDIATE read-macro character. NONIMMEDIATE, NONIMMED character is a normal character with respect to the line buffering, and so will not be activated until a carriage-return or matching right parenthesis or bracket is seen. NONIMMEDIATE is the default option for IMMEDIATE and NONIMMEDIATE. ------------------------------------------------------------------------ 38 Note that as a result, characters typed before an IMMEDIATE read-macro character cannot be erased by control-A or control-Q once the IMMEDIATE character has been typed, since they have already passed through the linebuffer. 39 Making a read-macro character be both ALONE and IMMEDIATE is a contradiction, since ALONE requires that the next character be input in order to see if it is a break or separator character. Thus, ALONE read-macros are always NONIMMEDIATE, regardless of whether or not IMMEDIATE is specified. 40 i.e., as soon as it is read, not as soon as it is typed. Characters that cause action as soon as they are typed are interrupt characters (see Section 16). 14.22 Note that read-macro characters can be "nested". For example, if = is defined by (MACRO (LAMBDA (FL RDTBL) (EVAL (READ FL RDTBL)))) and ! by (SPLICE (LAMBDA (FL RDTBL) (READ FL RDTBL))), then if the value of foo is (A B C), and (X =FOO Y) is input, (X (A B C) Y) will be returned. If (X !=FOO Y) is input, (X A B C Y) will be returned. Note that if a read-macro's function calls read, and the read returns NIL, the function cannot distinguish the case where a RIGHTPAREN or RIGHTBRACKET followed the read-macro character, e.g., (A B '), from the case where the atom NIL (or "()") actually appeared. Thus the first case is disallowed, i.e., reading a single RIGHTPAREN or RIGHTBRACKET via a read inside of a read-macro function. If this occurs, the paren/bracket will be put back into the input buffer, and a 41 READ-MACRO CONTEXT ERROR will be generated. readmacros[flg;rdtbl] If flg=NIL, turns off action of readmacros in rdtbl. If flg=T, turns them on. Value is previous setting. inreadmacrop[] value is NIL if currently not under a read-macro function, otherwise the number of unmatched left parentheses or brackets. setreadmacroflg[flg] resets the "read-macro" flag, i.e., the internal system flag that informs read that it is under a read macro function, and causes it to generate a READ-MACRO CONTEXT ERROR, if an unmatched ) or ] is encountered. Value is previous value of the flag. setreadmacroflg is useful when debugging read-macro functions to avoid spurious READ-MACRO CONTEXT error messages when typing into breaks, e.g., the user can simply put (SETREADMACROFLG) on breakresetforms (see Section 15). TERMINAL TABLES A readtable contains input/output information that is media-independent. For example, the action of parentheses is the same regardless of the device from which the input is being performed. A terminal table is a ------------------------------------------------------------------------ 41 If a call to read from within a readmacro encounters an unmatched RIGHTBRACKET within a list, the bracket is also put back into the buffer to be read (again) at the higher level. Thus, inputting an expression such as (A B '(C D] will work correctly. 14.23 42 datum that contains those syntax classes of characters that pertain to terminal input/output operations only, e.g., DELETECHAR (control-A), DELETELINE (control-Q), etc. In addition, terminal tables contain such information as how line-buffering is to be performed, how control characters are to be echoed/printed, whether lower case input is to be converted to upper case, etc. Using the functions below, the user may change, reset, or copy terminal tables. He can also create his own terminal tables and install them as the primary terminal table via settermtable. However, unlike readtables, terminal tables cannot be passed as arguments to input/output functions. TERMINAL TABLE FUNCTIONS termtablep[ttbl] value is ttbl, if ttbl is a real terminal table, NIL otherwise. gettermtable[ttbl] If ttbl=NIL, value is primary (i.e., current) terminal table. If ttbl is a real terminal table, value is ttbl. Otherwise, generates an ILLEGAL TERMINAL TABLE error. settermtable[ttbl] resets primary terminal table to be ttbl. Value is previous ttbl. Generates an ILLEGAL TERMINAL TABLE error if ttbl is not a real terminal table. copytermtable[ttbl] value is a copy of ttbl. ttbl can be a real terminal table, NIL, or ORIG, in which case value is a copy of the original system terminal table. Note that copytermtable is the only function that creates a terminal table. resettermtable[ttbl;from] smashes from into ttbl. from and ttbl can be NIL or a real terminal table. In addition, from can be ORIG, meaning use system's original terminal table. getsyntax, setsyntax, and syntaxp all work on terminal tables as well as readtables. When given NIL as a table argument, getsyntax and syntaxp use the primary readtable or primary terminal table depending on which table contains the indicated class argument, e.g., setsyntax[ch;BREAK] will refer to the primary readtable, setsyntax[ch;CHARDELETE] will refer to the primary terminal table. In the absence of such information, all ------------------------------------------------------------------------ 42 In INTERLISP-10, terminal tables are represented (currently) by 16 word arrays. 14.24 three functions default to the primary readtable, e.g., setsyntax[ch1;ch2] refers to the primary read table. If given incompatible class and table arguments, all three functions generate errors, e.g., setsyntax[ch;BREAK;ttbl], where ttbl is a terminal table, generates an ILLEGAL READTABLE error, getsyntax[CHARDELETE;rdtbl] an ILLEGAL TERMINAL TABLE error. TERMINAL SYNTAX CLASSES There are currently six terminal syntax classes: CHARDELETE (or DELETECHAR), LINEDELETE (or DELETELINE), RETYPE, CTRLV (or CNTRLV), and 43 EOL. These classes correspond (initially) to the characters control-A, control-Q, control-R, control-V, and carriagereturn/linefeed. All other characters belong to terminal syntax class NONE. The classes CHARDELETE, LINEDELETE, RETYPE, CTRLV, and EOL can contain at most one character. When a new character is assigned one of these syntax classes by setsyntax, the previous character is disabled, i.e., reassigned the syntax class NONE, and the value of setsyntax will be the code for the previous character of that class, if any, otherwise NIL. TERMINAL CONTROL FUNCTIONS echocontrol[char;mode;ttbl] Used to indicate how control characters are to be echoed or printed. char is a character or character code. If mode=IGNORE, char is never printed. If mode=REAL, char itself will be printed. If mode=SIMULATE, output will be simulated. If mode=UPARROW, char will be printed as ^ followed by the corresponding alphabetic character. The value of echocontrol is the previous output mode for char. If mode=NIL, the value is the current output mode without changing it. Note that echoing information can be independently specified for control characters only. (However, the function echomode described below can be used to disable all echoing.) Therefore, if char is an alphabetic character (or code), it refers to the corresponding control character, e.g., echocontrol[A;UPARROW] makes control-A echo as ^A. All other values of char generate ILLEGAL ARG errors. echomode[flg;ttbl] If flg=T, turns echoing for terminal table ttbl on. If flg=NIL, turns echoing off. Value is previous setting. ------------------------------------------------------------------------ 43 On input from a terminal, the EOL character signals to the line buffering routine to pass the input back to the calling function. It also is used to terminate inputs to readline, page 14.13. In general, whenever the phrase carriage-return linefeed is used, what is meant is the character with terminal syntax class EOL. 14.25 deletecontrol[type;message;ttbl] used for specifying the output protocol when a CHARDELETE or LINEDELETE is typed according to the following interpretations of type: LINEDELETE message is the message printed when LINEDELETE character is typed. Initially "#". 1STCHDEL message is the message printed the first time CHARDELETE is typed. Initially "\". NTHCHDEL message is the message printed on subsequent CHARDELETE's (without intervening characters). Initially "". POSTCHDEL message is the message printed when input is resumed following a sequence of one or more 44 CHARDELETE's. Initially "\". EMPTYCHDEL message is the message printed when a CHARDELETE is typed and there are no characters in the buffer. Initially "#". ECHO the characters deleted by CHARDELETE are echoed. NOECHO the characters deleted by CHARDELETE are not echoed. For LINEDELETE, 1STCHDEL, NTHCHDEL, POSTCHDEL, and EMPTYCHDEL, the message to be printed must be less than 5 characters. The value of deletecontrol will be the previous message as a string. If message=NIL, the value will be the previous message without changing it. For ECHO and NOECHO, the value of deletecontrol is the previous echo mode, i.e., ECHO or NOECHO. message is ignored. Note: If the user's terminal is a scope terminal, deletecontrol and echocontrol can be used to make it really delete the last character by performing the following: echocontrol[8;REAL], (8 is code for control-H, which is backspace) deletecontrol[NOECHO], (eliminates echoing of deleted characters) deletecontrol[1STCHDEL;"^H ^H"], and deletecontrol[NTHCHDEL;"^H ^H"]. ------------------------------------------------------------------------ 44 This setting of 1STCHDEL, NTHCHDEL, and POSTCHDEL makes it easy to determine exactly what has been deleted, namely all of the characters between the \'s. 14.26 raise[flg;ttbl] If flg=T, input is echoed as typed, but lowercase letters are converted to upper case. If flg=NIL, all characters are passed as typed. 45 Value is previous setting. LINE-BUFFERING AND CONTROL In INTERLISP's normal state, characters typed on the terminal (this section does not apply in any way to input from a file) are transferred to a line buffer. Characters are transmitted from the line buffer to whatever input function initiated the request (i.e., read, ratom, 46 47 48 rstring, or readc) when a carriage-return is typed. Until this time, the user can delete characters one at a time from the input buffer by typing control-A. The characters are echoed preceded by a \. Or, the user can delete the entire line buffer back to the last carriage-return 49 by typing control-Q, in which case INTERLISP echoes ##. (If no characters are in the buffer and either control-A or control-Q is typed, ------------------------------------------------------------------------ 45 In INTERLISP-10, both raise[] and raise[T] execute TENEX JSYS calls corresponding to the TENEX command NORAISE. Conversion of lowercase characters to uppercase before echoing is also available via raise[0], which executes the JSYS calls corresponding to the TENEX command RAISE. The conversion is then performed at the TENEX level, i.e., before INTERLISP-10 even sees the characters. The initial setting of raise in INTERLISP-10 is determined by the terminal mode at the time the user first starts up the system. Following a sysin, the raise mode is restored to whatever it was prior to the corresponding sysout. 46 peekc is an exception; it returns the character immediately. 47 i.e., the character with terminal syntax class EOL. 48 As mentioned earlier, for calls from read, the characters are also transmitted whenever the parentheses count reaches 0. In this case, if the third argument to read is NIL, INTERLISP also outputs a carriage-return line-feed. The characters are also transmitted whenever an IMMEDIATE read-macro character is typed. 49 Typing rubout clears the entire input buffer at the time it is typed, whereas the action of control-A and control-Q occurs at the time they are read. Rubout can thus be used to clear type-ahead. 14.27 50 INTERLISP echoes ##.) Note that this line editing is not performed by read or ratom, but by INTERLISP, i.e., it does not matter (nor is it necessarily known) which function will ultimately process the characters, only that they are still in the INTERLISP input buffer. Note also that it is the function that is currently requesting input that determines whether parentheses counting is observed, e.g., if the user executes (PROGN (RATOM) (READ)) and types in A (B C D) he will have to type in the carriage-return following the right parenthesis before any action is taken, whereas if he types (PROGN (READ) (READ)) he would not. However, once a carriage-return has been typed, the entire line is "available" even if not all of it is processed by the function initiating the request for input, i.e., if any characters are "left over", they will be returned immediately on the next request for input. For example, (PROGN (RATOM) (READC)) followed by A B carriage-return will perform both operations. TURNING-OFF LINE-BUFFERING The function control is available to defeat this line-buffering. After control[T], characters are returned to the calling function without line-buffering as described below. The function that initiates the request for input determines how the line is treated: 1. read if the expression being typed is a list, the effect is the same as though control were NIL, i.e., line-buffering until carriage-return or matching parentheses. If the expression being typed is not a list, it 51 is returned as soon as a break or separator character is encountered, e.g., (READ) followed by ABC space will immediately return ABC. Control-A and control-Q editing are available on those characters still in the buffer. Thus, if a program is performing several reads under control[T], and the user types NOW IS THE TIME followed by control-Q, he will delete only TIME since the rest of the line has already been transmitted to read and processed. ------------------------------------------------------------------------ 50 As described earlier, the CHARDELETE, LINEDELETE, and EOL characters can all be redefined. Therefore, references to control-A, control-Q, or carriage-return in the discussion actually refer to the current CHARDELETE, LINEDELETE, or EOL characters, whatever they may be. 51 An exception to the above occurs when the break or separator character is a (, ", or [, since returning at this point would leave the line buffer in a "funny" state. Thus if control is T and (READ) is followed by 'ABC(', the ABC will not be read until a carriage-return or matching parentheses is encountered. In this case the user could control-Q the entire line, since all of the characters are still in the buffer. 14.28 2. ratom characters are returned as soon as a break or separator character is encountered. Before then, control-A and control-Q may be used as with read, e.g., (RATOM) followed by ABCcontrol-Aspace will return AB. (RATOM) followed by (control-A will return ( and type ## indicating that control-A was attempted with nothing in the buffer, since the ( is a break character and would therefore already have been read. 3. readc/peekc the character is returned immediately; no line editing is possible. In particular, (READC) followed by control-A will read the control-A, (READC) followed by % will read the %. control[u;ttbl] u=T eliminates INTERLISP's normal line-buffering for the terminal table ttbl. u=NIL restores line-buffering (normal). The value of control is its previous setting. 14.5 MISCELLANEOUS INPUT/OUTPUT CONTROL FUNCTIONS clearbuf[file;flg] Clears the input buffer for file. If file is T and flg is T, contents of INTERLISP's line buffer and the system buffer are saved (and can be obtained via linbuf and sysbuf described below). When either control-D,control-E, control-H, control-P, or control-S is typed, INTERLISP automatically does a clearbuf[T;T]. (For control-P and control-S, INTERLISP restores the buffer after the interaction. See Appendix 3.) linbuf[flg] if flg=T, value is INTERLISP's line buffer (as a string) that was saved at last clearbuf[T;T]. If flg=NIL, clears this internal buffer. sysbuf[flg] same as linbuf for system buffer. If both the system buffer and INTERLISP's line buffer are empty, the internal buffers associated with linbuf and sysbuf are not changed by a clearbuf[T;T]. bklinbuf[x] x is a string. bklinbuf sets INTERLISP's line buffer to x. If greater than 160 characters, first 160 taken. bksysbuf[x] x is a string. bksysbuf sets system buffer to x. The effect is the same as though the user typed x. 14.29 bklinbuf, bksysbuf, linbuf, and sysbuf provide a way of "undoing" a clearbuf. Thus if the user wants to "peek" at various characters in the buffer, he could perform clearbuf[T;T], examine the buffers via linbuf and sysbuf, and then put them back. 52 radix[n] Resets output radix to |n| with sign indicator the sign of n. For example, in INTERLISP-10, -9 will print as shown with the following radices: radix printing 10 -9 -10 68719476727 i.e., (2^36-9) 8 -11Q -8 777777777767Q Value of radix is its last setting. radix[] gives current setting without changing it. Initial setting is 10. fltfmt[n] In INTERLISP-10, sets floating format control to n (See TENEX JSYS manual for interpretation of n). fltfmt[T] specifies free format (see Section 3). Value of fltfmt is last setting. fltfmt[] returns current setting without changing it. Initial setting is T. linelength[n] Sets the length of the print line for all files. Value is the former setting of the line length. Whenever printing an atom would go beyond the length of the line, a carriage-return is automatically inserted first. linelength[] returns current setting. Initial setting is 72. position[file;n] Gives the column number the next character will be read from or printed to, e.g., after a carriage-return, position=0. If n is non-NIL, resets position to n. Note that position[file] is not the same as getfileptr[file] which gives the position in the file, not on the line. ------------------------------------------------------------------------ 52 Currently, there is no input radix. 14.30 14.6 SYSIN AND SYSOUT sysout[file] Saves the user's private memory on file. Also saves the stacks, so that if a program performs a sysout, the subsequent sysin will continue from that point, e.g., [PROGN (SYSOUT (QUOTE FOO)) (PRINT (QUOTE HELLO] will cause HELLO to be printed after (SYSIN (QUOTE FOO)) The value of sysout is file 53 (full name). A value of NIL indicates the sysout was unsuccessful, i.e., either disk or computer error, or user's directory was full. Sysout does not save the state of any open files. Whenever the INTERLISP system is reassembled and/or reloaded, old sysout files are not compatible with the new system. sysin[file] restores the state of INTERLISP from a sysout 54 file. Value is list[file]. If sysin returns NIL, there was a problem in reading the file. If file is not found, generates a FILE NOT FOUND error. Since sysin continues immediately where sysout left off, the only way for a program to determine whether it is just coming back from a sysin or from a sysout is to test the value of sysout. For example, (COND ((LISTP (SYSOUT (QUOTE FOO))) (PRINT (QUOTE HELLO)))) will cause HELLO to be printed following the sysin, but not when the sysout was performed. ------------------------------------------------------------------------ 53 sysout is advised to set the variable sysoutdate to (DATE), i.e., the time and date that the sysout was performed. sysout is also advised to evaluate the expressions on aftersysoutforms when coming back from a sysin, i.e., when the value being returned by sysout is a list. 54 In INTERLISP-10, file is a runnable file, i.e., it is not necessary to start up an INTERLISP and call sysin in order to restore the state of the user's program. Instead, the user can treat the sysout file the same as a SAV file, i.e., use the TENEX RUN command, or simply type the file name to TENEX, and the effect will be exactly the same as having performed a sysin. 14.31 14.7 SYMBOLIC FILE INPUT readfile[file] Reads successive S-expressions from file using read (with filerdtbl as readtable) until the single atom STOP is read, or an end of file encountered. Value is a list of these S-expressions. load[file;ldflg;printflg] Reads successive S-expressions from file (with filerdtbl as readtable) and evaluates each as it is read, until it reads either NIL, or the single atom STOP. Value is file (full name). If printflg=T, load prints the value of each S-expression; otherwise it does not. ldflg affects the operation of define, defineq, rpaq, and rpaqq. While load is operating, dfnflg 55 (Section 8) is reset to ldflg. Thus, if ldflg=NIL, and a function is redefined, a message is printed and the old definition saved. If ldflg=T, the old definition is simply overwritten. If ldflg=PROP, the function definitions are stored on the property lists under the property EXPR. If ldflg=ALLPROP, not only function definitions but also variables set by rpaqq and rpaq are stored on property 56 lists. 57 loadfns[fns;file;ldflg;vars] permits selective loading of function definitions. fns is a list of function names, a single function name, or T, meaning all 58 functions. file can be either a compiled or ------------------------------------------------------------------------ 55 Using resetvar (Section 5). dfnflg cannot simply be rebound because it is a global variable. See Section 18. 56 except when the variable has value NOBIND, in which case it is set to the indicated value regardless of dfnflg. 57 loadfns was originally written by J. W. Goodwin, and subsequently modified by W. Teitelman. 58 If a compiled definition is loaded, so are all compiler generated subfunctions. 14.32 symbolic file, i.e., any file that can be loaded by load. The interpretation of ldflg is the same as for load. vars specifies which non-DEFINEQ expression are to be loaded (i.e., evaluated): T means all, NIL means none, VARS is same as (RPAQQ RPAQ), FNS/VARS is same as (fileCOMS fileBLOCKS), and any other atom is the same as list[atom]. When vars is a list, each atom on vars is compared with both car and cadr of non-DEFINEQ expressions, e.g., either RPAQQ or FOOCOMS can be used to indicate (RPAQQ FOOCOMS --) should be loaded. For more complicated specification, each list on vars is treated as an edit pattern and matched with the entire non-DEFINEQ expression. In other words, a non-DEFINEQ expression will be loaded if either its car or cadr is eq to some member of vars, or it matches (using edit4e) some list on vars, e.g., (FOOCOMS DECLARE: (DEFLIST & (QUOTE MACRO))) would cause (RPAQQ FOOCOMS --), all DECLARE:'s, and all DEFLIST's which set up MACRO's to be read and evaluated. The value of loadfns is a list of (the names of) the functions that were found, plus a list of those functions not found (if any) headed by the atom NOT-FOUND: e.g., (FOO FIE (NOT-FOUND: FUM)). If vars is non-NIL, the value will also include those expressions that were loaded, plus a list of those members of vars for which no corresponding expressions were found (if any), again headed by the atom NOT-FOUND:. If file=NIL, loadfns will use whereis (page 14.61) to determine where the first function in fns resides, and load from that file. Note that the file must previously have been "noticed". (For more discussion, see page 14.53). loadvars[vars;file;ldflg] same as loadfns[NIL,file;ldflg;vars] loadfrom[file;fns;ldflg]same as loadfns[fns;file;ldflg;T] As mentioned in Section 9, once the file package knows about the contents of a file, the user can edit functions contained in the file without explicitly loading them. Similarly, those functions which have not been modified do not have to be loaded in order to write out an updated version of the file. Files are normally noticed, i.e., their contents become known to the file package (page 14.52), when either the symbolic or compiled versions of the file are loaded. If the file is not going to be loaded, the preferred way to notice it is with loadfrom. 14.33 For example, if the user wants to update the file FOO by editing the function FOO1 contained in it, he need only perform loadfrom[FOO], edit[FOO1], and makefile[FOO]. Note that the user can also load some functions at the same time by giving loadfrom a second argument, e.g., loadfrom[FOO;FOO1], but its raison d'etre is to inform the file package about the existence and contents of a particular file. loadblock[fn;file;ldflg]calls loadfns on those functions contained in 59 the block declaration containing fn. loadefs[fns;file] like loadfns except returns a list of functions and their symbolic definitions, plus a list of those functions not found, if any, headed by the atom NOT-FOUND:, e.g., loadfns[(FOO FIE FUM);FOO] = ((FOO (LAMBDA ...)) (FIE (LAMBDA ...)) (NOT-FOUND: FUM)). FILE MAPS A file map is a data structure which contains a symbolic 'map' of the contents of a file. Currently, this consists of the begin and end 60 address for each defineq expression in the file, the begin and end address for each function definition within the defineq, and the begin 61 and end address for each compiled function. makefile, prettydef, loadfns, recompile, and numerous other system functions depend heavily on the file map for efficient operation. For example, the file map enables loadfns to load selected function definitions simply by setting the file pointer to the corresponding address using setfileptr, and then performing a single read. Similarly, the file map is heavily used by the "remake" option of prettydef (page 14.57) those function definitions that have been changed since the previous version are prettyprinted; the rest are simply copied from the old file to the new one, resulting in a considerable speedup. ------------------------------------------------------------------------ 59 loadblock is designed primarily for use with symbolic files, i.e., to load the exprs for a given block. It will not load a function which already has an in-core expr definition, and it will not load the block name, unless it is also one of the block functions. 60 byte address, see getfileptr, page 14.5. 61 The internal representation of the file map is not documented since it may change when the map is extended to include information about other than just function definitions. 14.34 Whenever a file is read by load or loadfns, a file map is automatically 62 63 built and stored on the property list of the root name of the file, under the property FILEMAP. Whenever a file is written by prettydef, a file map for the new file is also built and stored on the FILEMAP 64 65 property. In addition, the file map is written on the file itself. Thus, in most cases, load and loadfns do not have to build the file map at all, since a file map will usually appear in the corresponding 66 file. The procedure followed whenever a system package that uses file maps accesses a file is embodied in the function getfilemap. getfilemap first checks the FILEMAP property to see if a file map for this file was 67 previously obtained or built. If there is none, getfilemap next checks the first expression on the file to see if it is a FILECREATED ------------------------------------------------------------------------ 62 unless buildmapflg=NIL. buildmapflg is initially T. 63 the file name with directory and version number stripped off. 64 Building the map in this case essentially comes for free, since it requires only reading the current file pointer before and after each definition is written or copied. However, building the map does require that prettyprint know that it is printing a DEFINEQ expression. For this reason, the user should never print a DEFINEQ expression onto a file himself, but should instead always use the FNS command, page 14.41. 65 For cosmetic reasons, the file map is written as the last expression in the file. However, the address of the file map in the file is (over)written into the FILECREATED expression that appears at the beginning of the file so that the file map can be rapidly accessed without having to scan the entire file. 66 unless the file was written with buildmapflg=NIL, or was written outside of INTERLISP. 67 The full name of the file is also stored on the FILEMAP property along with its map. 14.35 68 expression that also contains the address of a FILEMAP. If neither are 69 70 successful getfilemap returns NIL, , and a file map will be built. 14.8 SYMBOLIC FILE OUTPUT writefile[x;file] Writes a date expression onto file, followed by successive S-expressions from x, using filerdtbl as a readtable. If x is atomic, its value is used. If file is not open, it is opened. If file is a list, car[file] is used and the file is left opened. Otherwise, when x is finished, a STOP is printed on file and it is closed. Value is file. pp[x] nlambda, nospread function that performs output[T], setreadtable[T] and then calls prettyprint: PP FOO is equivalent to PRETTYPRINT((FOO)); PP(FOO FIE) or (PP FOO FIE) is equivalent to PRETTYPRINT((FOO FIE)). Primary output file and primary readtable are restored after printing. ------------------------------------------------------------------------ 68 currently, file maps for compiled files are not written onto the files themselves. However, load and loadfns will build maps for a compiled file when it is loaded, and store it on the property FILEMAP. Similary, loadfns will obtain and use the file map for a compiled file, when available. 69 getfilemap also returns NIL, if usemapflg=NIL, initially T. usemapflg is available primarily to enable the user to recover in those cases where the file and its map for some reason do not agree. For example, if the user edits a symbolic file that contains a map using a text editor such as TECO, inserting or deleting just one character will throw that map off. The functions which use file maps contain various integrity checks to enable them to detect that something is wrong, and to generate the error FILEMAP DOES NOT AGREE WITH CONTENTS OF file-name. In such cases, the user can set usemapflg to NIL, causing the map contained in the file to be ignored, and then reexecute the operation. A new map will then be built (unless buildmapflg is also NIL). 70 While building the map will not help this operation, it will help in future references to this file. For example, if the user performs loadfrom[FOO] where FOO does not contain a file map, the loadfrom will be (slightly) slower than if FOO did contain a file map, but subsequent calls to loadfns for this version of FOO will be able to use the map that was built as the result of the loadfrom, since it will be stored on FOO's FILEMAP property. 14.36 71 72 prettyprint[lst] lst is a list of functions (if atomic, its value is used). The definitions of the functions are printed in a pretty format on the primary output file using the primary readtable. For example, (FACTORIAL [LAMBDA (N) (COND ((ZEROP N) 1) 73 (T (ITIMES N (FACTORIAL (SUB1 N]) Note: prettyprint will operate correctly on functions that are broken, broken-in, advised, or have been compiled with their definitions saved on their property lists - it prints the original, pristine definition, but does not change the current state of the function. If prettyprint is given an atom which is not the name of a function, but 74 has a value, it will prettyprint the value. Otherwise, prettyprint will perform spelling correction. If all fails, prettyprint returns (atom NOT PRINTABLE). COMMENT FEATURE A facility for annotating INTERLISP functions is provided in prettyprint. Any S-expression beginning with * is interpreted as a comment and printed in the right margin. Example: ------------------------------------------------------------------------ 71 The prettyprint package was written by W. Teitelman. 72 prettyprint has a second argument that is T when called from prettydef. In this case, whenever prettyprint starts a new function, it prints (on the terminal) the name of that function if more than 30 seconds (real time) have elapsed since the last time it printed the name of a function. 73 In order to save space on files, tabs are used instead of spaces for the inital spaces on each line, assuming that each tab corresponds to 8 spaces. This results in a reduction of file size by about 30%. Tabs will not be used if prettytabflg is set to NIL (initially T). 74 except when prettyprint is called from prettydef. 14.37 (FACTORIAL [LAMBDA (N) (* COMPUTES N!) (COND ((ZEROP N) (* 0!=1) 1) (T (* RECURSIVE DEFINITION: N!=N*N-1!) (ITIMES N (FACTORIAL (SUB1 N]) These comments actually form a part of the function definition. Accordingly, * is defined as an NLAMBDA NOSPREAD function that returns its argument, i.e., it is equivalent to quote. When running an interpreted function, * is entered the same as any other INTERLISP function. Therefore, comments should only be placed where they will not harm the computation, i.e., where a quoted expression could be placed. For example, writing (ITIMES N (FACTORIAL (SUB1 N)) (* RECURSIVE DEFINITION)) in the above function would cause an error when ITIMES attempted to multiply N, N-1!, and RECURSIVE. For compilation purposes, * is defined as a macro which compiles into no instructions. Thus, if you compile a function with comments, and load the compiled definition into another system, the extra atom and list structures storage required by the comments will be eliminated. This is the way the comment feature is intended to be used. For more options, see end of this section. Comments are designed mainly for documenting listings. Thus when prettyprinting to the terminal, comments are suppressed and printed as 75 the string **COMMENT**. The comment map feature provides a way of saving space by keeping the text of the comments on the file (see page 14.48). PRETTYDEF 76 prettydef[prttyfns;prttyfile;prttycoms] Used to make symbolic files that are suitable for loading which contain function definitions, variable settings, property lists, et al, in a prettyprint format. prettydef uses filerdtbl as its readtable. The value of prettydef is the ------------------------------------------------------------------------ 75 The value of **comment**flg determines the action. If **comment**flg is NIL, the comment is printed. Otherwise, the value of **comment**flg is printed. **comment**flg is initially set to " **COMMENT** ". The function pp* is provided to prettyprint functions, including their comments, to the terminal. pp* operates exactly like pp except it first sets **comment**flg to NIL. 76 prettydef actually has three additional arguments for use by the file package. See discussion of remaking a file, page 14.58. 14.38 name of the symbolic file that was created. prettydef operates under a resetlst (see Section 5). If an error occurs, or a control-D is typed, all files that prettydef has opened will be closed, the (partially complete) file being written will be deleted, and any undoable 77 operations executed will be undone. The arguments to prettydef are interpreted as follows: prttyfns is a list of function names. The functions on the list are prettyprinted surrounded by a (DEFINEQ ...) so that they can be loaded with load. If prttyfns is atomic (the preferred usage), its top level value is used as the list 78 of function names, and an rpaqq will also be written which will set that atom to the list of functions when the file is loaded. A print expression will also be written which informs the user of the named atom or list of functions 79 when the file is subsequently loaded. prttyfile is the name of the file on which the output is to be written. The following options exist: prttyfile=NIL The primary output file is used. prttyfile atomic The file is opened if not already open, and becomes primary output file. File is closed at end of prettydef and primary output file is restored. ------------------------------------------------------------------------ 77 Since prettydef operates under a resetlst, any resetsaves executed in the course of the prettydef will also be protected, i.e., restored. For example, if one of the prettydef commands executes a (RESETSAVE (LINELENGTH 100)), the linelength will atomatically be restored. 78 rpaqq and rpaq are like setqq and setq, except they set the top level value. See Section 5. 79 In addition, if any of the functions in the file (including those printed by FNS command) are nlambdas, prettydef will print a DECLARE: expression suitable for informing the compiler about these functions, in case the user recompiles the file without having first loaded the nlambda functions. For more discussion, see Section 18. 14.39 prttyfile a list Car of the list is assumed to be the file name, and is opened if not already open. The file is left open at end of prettydef. prttycoms Is a list of commands interpreted as described below. If prttycoms is atomic (the preferred usage), its top level value is used and an rpaqq is written which will set that atom to the list of commands when the file is subsequently loaded, exactly as with prttyfns. These commands are used to save on the output file top level bindings of variables, property lists of atoms, miscellaneous INTERLISP forms to be evaluated upon loading, arrays, and advised functions. It also provides for evaluation of forms at output time. The interpretation of each command in the command list is as follows: 1. if atomic, an rpaqq is written which will restore the top level value of this atom when the file is loaded. 2. (PROP propname atom1 ... atomn) an appropriate expression will be written which will restore the value of propname for each atomi when 80 the file is loaded. If propname is a list, expressions will be written for each property on that list. If propname=ALL, the values of all user properties (on the property list of each atomi) are 81 saved. 3. (ARRAY atom1 ... atomn), each atom following ARRAY should have an array as its value. An appropriate expression will be written which will set the atom to an array of exactly the same size, type, and contents upon loading. 4. (P . expression), each S-expression following P will be printed on the output file, and consequently evaluated when the file is loaded. ------------------------------------------------------------------------ 80 If atomi does not have the property propname (as opposed to having the property with NIL value), a warning message "NO propname PROPERTY FOR atomi" is printed. The command IFPROP should be used if it is not known whether or not an atom will have the corresponding property. 81 sysprops is a list of properties used by system functions. Only properties not on that list are dumped when the ALL option is used. 14.40 5. (E . forms), each form following E will be evaluated at output time, i.e., when prettydef reaches this command. 6. (FNS fn1 ... fnm), a defineq is written with the definitions of fn1 ... fnm exactly as though (fn1 ... fnm) were the first argument 82 to prettydef. 7. (VARS var1 ... varn), for each vari, an expression will be written which will set its top level value when the file is loaded. If vari is atomic, vari will be set to the top-level value it had at the time the file was prettydefed, i.e., (RPAQQ vari top-level-value) is 83 written. If vari is non-atomic, it is interpreted as (var form). e.g., (FOO (APPEND FIE FUM)) or (FOO (QUOTE (FOO1 FOO2 FOO3))). In this case the expression (RPAQ var form) is written. 8. (ADVISE fn1 ... fnm), for each fnn, an appropriate expression will be written which will reinstate the function to its advised state when the file is loaded. 9. (ADVICE fn1 ... fnm,), for each fni, will write a deflist which will put the advice back on the property list of the function. The user can then use readvise to reactivate the advice. See Section 19. 10. (BLOCKS block1 ... blockn), for each blocki, a declare expression will be written which the block compile functions interpret as block declarations. See Section 18. 11. (COMS com1 ... comn), each of the commands com1 ... comn will be interpreted as a prettydef command. 12. (ADDVARS (var1 . lst1) ... (varn . lstn)), Each element of lsti not a member of vari (at load time) is added to it, i.e., the new value of vari will be the union of its old value and lsti (not the value of lsti). vari can initially be NOBIND, in which case it is first set to NIL. ------------------------------------------------------------------------ 82 The user should never print a DEFINEQ expression directly onto a file himself, but should instead always use the FNS command for dumping functions. For more details, see page 14.35. 83 HORRIBLEVARS (Section 21) provides a way of saving and reloading variables whose values contain re-entrant or circular list structure, user data types, arrays, or hash arrays. 14.41 13. (USERMACROS atom1 ... atomn), each atomi is the name of a user edit macro. USERMACROS writes expressions for adding the definitions to usermacros and the names to the appropriate spelling lists. (USERMACROS) will save all user edit macros. 14. (IFPROP propname atom1 ... atomn), same as PROP command, except that only non-NIL property values are saved. For example, if FOO1 has property PROP1 and PROP2, FOO2 has PROP3, and FOO3 has property PROP1 and PROP3, (IFPROP (PROP1 PROP2 PROP3) FOO1 FOO2 FOO3) will save only those 5 property values. 15. (DECLARE: . prettycoms/flags), Normally expressions written onto a symbolic file are (1) evaluated when loaded; (2) copied to the compiled file when the symbolic file is compiled (see Section 18); and (3) not evaluated at compile time. DECLARE: allows the user to override these defaults. The output of those prettycoms appearing within the DECLARE: command is embedded in a DECLARE: expression, along with any tags that are specified, e.g., (DECLARE: EVAL@COMPILE DONTCOPY (FNS --) (PROP --)) would produce (DECLARE: EVAL@COMPILE DONTCOPY (DEFINEQ --) (DEFLIST --)). DECLARE: is defined as an nlambda nospread function. When declare: is called, it processes its arguments by evaluating or not evaluating each list depending on the setting of an internal state variable. The tags EVAL@LOAD, or DOEVAL@LOAD, and DONTEVAL@LOAD can be used to reset this state variable. The initial setting is to 84 evaluate. 16. (PRETTYDEFMACROS . macronames) For each macro, expressions are written which will redefine the macro, as well as working the necessary additions to prettycomsplst, prettytypelst, and restoring the PRETTYTYPE property, if any. 17. (* . text), Used for inserting a comment in a file. First a form- feed is printed, then the comment. ------------------------------------------------------------------------ 84 As indicated in Section 18, DECLARE: expressions are specially processed by the compiler. In this case, the relevant tags are COPY, DOCOPY, DONTCOPY, EVAL@COMPILE, DOEVAL@COMPILE, and DONTEVAL@COMPILE. The value of declaretagslst is a list of all the tags used in DECLARE: expressions. If a tag not on this list appears in a DECLARE: prettycom, prettydef performs spelling correction using declaretagslst as a spelling list. 14.42 In each of the commands described above, if the atom * follows the command type, the form following the *, i.e., caddr of the command, is evaluated and its value used in executing the command, e.g., 85 (FNS * (APPEND FNS1 FNS2)). Note that (COMS * form) provides a way of computing what should be done by prettydef. New prettydef commands can be defined via prettydefmacros (see page 14.47), and dumped via the PRETTYDEFMACROS command. If prettydef is given a command not one of the above, and not defined on 86 prettydefmacros, it attempts spelling correction using prettycomsplst as a spelling list. If successful, the corrected version of prettycoms 87 is written (again) on the output file. If unsuccessful, prettydef generates an error, BAD PRETTYCOM. Example: _SET(FOOFNS (FOO1 FOO2 FOO3)) _SET(FOOCOMS(FIE (PROP MACRO FOO1 FOO2) (P (MOVD (QUOTE FOO1) (QUOTE FIE1] _PRETTYDEF(FOOFNS FOO FOOCOMS) would create a file FOO containing: 1. (FILECREATED "time and date the file was made" . "other information") 2. (DEFINEQ "definitions of FOO1, FOO2, and FOO3") 3. (PRETTYCOMPRINT FOOFNS) 4. (RPAQQ FOOFNS (FOO1 FOO3 FOO3)) 5. (PRETTYCOMPRINT FOOVARS) 6. (RPAQQ FOOVARS (FIE ...) 7. (RPAQQ FIE "value of FIE") ------------------------------------------------------------------------ 85 Except for the PROP and IFPROP commands, in which case the * must follow the property name, e.g., (PROP MACRO * FOOMACROS). 86 unless dwimflg=NIL. See Section 17. 87 since at this point, the uncorrected prettycoms would already have been printed on the output file. When the file is loaded, this will result in prettycoms being reset, and a message printed, e.g., (FOOVARS RESET). The value of FOOVARS would then be the corrected version. 14.43 8. (PUTPROPS FOO1 MACRO propvalue) 9. (PUTPROPS FOO2 MACRO propvalue) 10. (MOVD (QUOTE FOO1) (QUOTE FIE1)) 11. STOP PRETTYDEF FUNCTIONS printfns[x] x is a list of functions. printfns prints defineq and prettyprints the functions to primary output file using primary readtable. Used by prettydef, i.e., command (FNS * FOO) is equivalent to command (E (PRINTFNS FOO)). printdate[file;changes] prints the filecreated expression at beginning of prettydef files. changes is for use by the file package. filecreated[x] Nlambda function. Prints a message (using lispxprint) followed by the time and date the file was made, which is car[x]. The message is the value of prettyheader, initially "FILE CREATED". If prettyheader=NIL, nothing is printed. cdr[x] contains information about the file, e.g., full name, address of file map, list of changed items, etc. filecreated also stores the time and date the file was made on the property list of the file under the property FILEDATES and performs other initialization for the file package. prettycomprint[x] prints x using lispxprint, unless value of prettyheader=NIL. tab[pos;minspaces;file] performs appropriate number of spaces to move to position pos. minspaces indicates the minimum number of spaces to be printed by tab, i.e., it is intended to be small number (if NIL, 1 is used). Thus, if position + minspaces is greater than pos, tab does a terpri and then spaces[pos]. endfile[file] Prints STOP on file and closes it. printdef[expr;left;def;tailflg] prints the expression expr in a pretty format on the primary output file using the primary readtable. left is the left hand margin (linelength determines the right hand margin.) 14.44 def=T means expr is a function definition, or a piece of one, i.e., prettyprint is essentially printdef[getd[fn];NIL;T]. If def=NIL, no special action will be taken for LAMBDA's, PROG's, COND's, comments, CLISP, etc. def is NIL when prettydef calls prettyprint to print variables and property lists, and when printdef is called from the editor via the command PPV. tailflg = T means expr is a tail of a list, and is printed without parentheses. comment1[l] prints the comment l. comment1 is a separate function to permit the user to intercept the printing of comments, perform some operation, e.g., reset the line length, print the comment himself, and then restore the line length. For example, this could be accomplished by adding (* LAMBDA (X) (RESETFORM (LINELENGTH 100) 88 (COMMENT1 X))) to prettyprintmacros. SPECIAL PRETTYPRINT AND PRETTYDEF CONTROLS All variables described below, i.e., #rpars, firstcol, et al, are global variables, see Section 18. Therefore, if they are to be changed, they must be reset, not rebound. prettyheader value is message printed by filecreated. prettyheader is initially "FILE CREATED". If prettyheader=NIL, neither filecreated nor prettycomprint will print anything. Thus, setting prettyheader to NIL will result in "silent loads". For example, prettyheader is reset to NIL during greeting (Section 22). #rpars controls the number of right parentheses necessary for square bracketing to occur. If #rpars=NIL, no brackets are used. #rpars is initialized to 4. linelength[n] determines the position of the right margin for ------------------------------------------------------------------------ 88 comment1 is an entry to the prettyprint block. However, it is called internally by prettyprint so that advising or redefining it will not affect the action of prettyprint. 14.45 89 prettyprint. firstcol is the starting column for comments. Initial setting is 48. Comments run between firstcol and linelength. If a word in a comment ends with a "." and is not on the list abbrevlst, and the position is greater than halfway between firstcol and linelength, the next word in the comment begins on a new line. Also, if a list is encountered in a comment, and the position is greater than halfway, the list begins on a new line. prettylcom If a comment is bigger (using count) than prettylcom in size, it is printed starting at 90 column 10, instead of firstcol. prettylcom is initialized to 14 (arrived at empirically). #carefulcolumns in the interests of efficiency, prettyprint approximates the number of characters in each atom, rather than calling nchars, when computing how much will fit on a line. This procedure works satisfactorily in most cases. However, users with unusually long atoms in their programs, e.g., such as produced by clispify, may occasionlly encounter some glitches in the output produced by prettyprint. The value of #carefulcolumns tells prettyprint how many columns (counting from the right hand margin) in which to actually compute nchars instead of approximating. Setting #carefulcolumns to 20 or 30 will eliminate the above glitches, although it will slow down prettyprint slightly. #carefulcolumns is initially 0. widepaper[flg] widepaper[T] sets filelinelength to 120, firstcol to 80, and prettylcom to 28. These are useful settings for prettyprinting files to be listed on wide paper. widepaper[] restores these parameters to their initial values. The value of widepaper is its previous setting. ------------------------------------------------------------------------ 89 Note that makefile, page 14.56, resets linelength to the value of filelinelength, before calling prettydef. filelinelength is initially 72. 90 Comments are also printed starting at column 10, if their second element is also a *, i.e., comments of the form (* * --). 14.46 commentflg If car of an expression is eq to commentflg, the expression is treated as a comment. commentflg is initialized to *. prettyflg If prettyflg is NIL, printdef uses prin2 instead of prettyprinting. This is useful for producing a fast symbolic dump (see FAST option of makefile, page 14.56). Note that the file loads the same as if it were prettyprinted. prettyflg is initially set to T. clispifyprettyflg used to inform prettyprint to CLISPIFY selected function definitions before printing them. See Section 23. prettydefmacros is an assoc-type list for defining substitution macros for prettydef. If (FOO (X Y) . coms) appears on prettydefmacros, then (FOO A B) appearing in the third argument to prettydef will cause A to be substituted for X and B for Y throughout coms (i.e., cddr of the macro), and then coms treated as a list of commands for 91 prettydef. If the atom * follows the name of the command, caddr of the command is evaluated before substituting in the definition for the command. prettyprintmacros is an assoc-list that enables the user to format selected expressions himself. car of each expression being prettyprinted is looked up on prettyprintmacros, and if found, cdr of the corresponding entry is applied to the expression. If the result of this application is NIL, prettyprint will ignore the expression.This gives the user the option of printing the expression himself in whatever format he pleases. If the result is non-NIL, it is prettyprinted in the normal fashion. This gives the user the option of computing some other expression to be prettyprinted in its place. prettyprintmacros is initially NIL. prettyprintypemacros is a list of elements of the form ------------------------------------------------------------------------ 91 The substitution is carried out by subpair (Section 6), so that the "argument list" for the macro can also be atomic. For example, if (FOO X . COMS) appears on prettydefmacros, then (FOO A B) will cause (A B) to be substituted for X throughout coms. 14.47 (type-number . fn). For typenumbers other than 8 (lists) and 12 (atoms), the type number is looked up on prettyprintypemacros, and if found, the corresponding function is applied to the datum about to be printed, instead of simply printing it with prin2. prettyprintypemacros is initially NIL. changechar if non-NIL, and prettyprint is printing to a file or display terminal, prettyprint prints changechar in the right hand margin while printing those expressions marked by the editor as having been changed (see Section 9). changechar is initially |. (* E x) A comment of this form causes x to be evaluated at prettyprint time, e.g., (* E (RADIX 8)) as a comment in a function containing octal numbers can be used to change the radix to produce more readable printout. The comment is also printed. COMMENT POINTERS For a well-commented collection of programs, the list structure, atom, and pname storage required to represent the comments in core can be significant. If the comments already appear on a file and are not needed for editing, a significant savings can be achieved by simply leaving the text of the comment on the file when the file is loaded, and instead retaining in core only a pointer to the comment. This feature has been implemented by defining * as a read-macro in FILERTBL which instead of reading in the entire text of the comment, constructs an expression containing [1] the name of the file in which the text of the comment is contained, [2] the address of the first byte of the comment, 92 and [3] the number of bytes. For output purposes, * is defined as a prettyprintmacro that prints the comments represented by such pointers by simply copying the corresponding bytes from one file to another, or to the terminal. Normal comments are processed the same as before, and can be intermixed freely with comment pointers. The comment pointer feature is enabled by setting normalcommentsflg to NIL. normalcommentsflg is initially T. Note that normalcommentsflg can be changed as often as desired, i.e., some files can be loaded normally, and others using comment pointers. For convenience of editing selected comments, an edit macro, get*, is ------------------------------------------------------------------------ 92 Plus a flag to indicate whether the comment appeared at the right hand margin or centered on the page. 14.48 93 included which loads in the text of the corresponding comment. ------------------------------------------------------------------------ 93 pp* prints the comment without reading it by simply copying the corresponding bytes to the terminal. 14.49 CONVERTING COMMENTS TO LOWER CASE This section is for users operating on terminals without lower case who nevertheless would like their comments to be converted to lower case for more readable line-printer listings. Users with lower-case terminals can skip to the File Package sections (as they can type comments directly in lower case). %% If the second atom in a comment is %%, the text of the comment is converted to lower case so that it looks like English instead of LISP (see next page). The output on the next page illustrates the result of a lower casing operation. Before this function was prettydefed, all comments consisted of upper case atoms, e.g., the first comment was (* %% INTERPRETS A SINGLE COMMAND). Note that comments are converted only when they are actually written to a file by prettydef. The algorithm for conversion to lower case is the following: If the first character in an atom is ^, do not change the atom (but remove the 94 ^). If the first character is %, convert the atom to lower case. If 95 96 the atom is an INTERLISP word, do not change it. Otherwise, convert the atom to lower case. Conversion only affects the upper case alphabet, i.e., atoms already converted to lower case are not changed if the comment is converted again. When converting, the first character in the comment and the first character following each period are left capitalized. After conversion, the comment is physically modified to be the lower case text minus the %% flag, so that conversion is thus only performed once (unless the user edits the comment inserting additional upper case text and another %% flag). ------------------------------------------------------------------------ 94 User must type %% as % is the escape character. 95 minus any trailing punctuation marks. 96 i.e., is a bound or free variable for the function containing the comment, or has a top level value, or is a defined function, or has a non-NIL property list. 14.50 (BREAKCOM [LAMBDA (BRKCOM BRKFLG) (* Interprets a single command.) (PROG (BRKZ) TOP (SELECTQ BRKCOM [^ (RETEVAL (QUOTE BREAK1) (QUOTE (ERROR]] (GO (* Evaluate BRKEXP unless already evaluated, print value, and exit.) (BREAKCOM1 BRKEXP BRKCOM NIL BRKVALUE) (BREAKEXIT)) (OK (* Evaluate BRKEXP, unless already evaluated, do NOT print value, and exit.) (BREAKCOM1 BRKEXP BRKCOM BRKVALUE BRKVALUE) (BREAKEXIT T)) (^WGO (* Same as GO except never saves evaluation on history.) (BREAKCOM1 BRKEXP BRKCOM T BRKVALUE) (BREAKEXIT)) (RETURN (* User will type in expression to be evaluated and returned as value of BREAK. Otherwise same as GO.) (BREAKCOM1 [SETQ BRKZ (COND (BRKCOMS (CAR BRKCOMS)) (T (LISPXREAD T] (QUOTE RETURN) NIL NIL (LIST (QUOTE RETURN) BRKZ)) (BREAKEXIT)) (EVAL (* Evaluate BRKEXP but do not exit from BREAK.) (BREAKCOM1 BRKEXP BRKCOM) (COND (BRKFLG (BREAK2) (PRIN1 BRKFN T) (PRIN1 (QUOTE " EVALUATED ") T))) (SETQ !VALUE (CAR BRKVALUE)) (* For user's benefit.) ) 14.51 lcaselst Words on lcaselst will always be converted to lower case. lcaselst is initialized to contain words which are INTERLISP functions but also appear frequently in comments as English words. e.g., AND, EVERY, GET, GO, LAST, LENGTH, LIST, etc. Thus, in the example on the previous page, not was written as ^NOT, and GO as ^GO in order that they might be left in upper case. ucaselst words on ucaselst (that do not appear on lcaselst) will be left in upper case. ucaselst is initialized to NIL. abbrevlst abbrevlst is used to distinguish between abbreviations and words that end in periods. Normally, words that end in periods and occur more than halfway to the right margin cause carriage-returns. Furthermore, during conversion to lowercase, words ending in periods, except for those on abbrevlst, cause the first character in the next word to be capitalized. abbrevlst is initialized to the upper and lower case forms of ETC. I.E. and E.G. l-case[x;flg] value is lower case version of x. If flg is T, the first letter is capitalized, e.g., l-case[FOO;T] = Foo, l-case[FOO] = foo. If x is a string, the value of l-case is also a string, e.g., l-case["FILE NOT FOUND";T] = "File not found". u-case[x] Similar to l-case 97 14.9 FILE PACKAGE This section describes a set of functions and conventions for facilitating the bookkeeping involved with working in a large system consisting of many symbolic files and their compiled counterparts. The file package keeps track of which files have been in some way modified and need to be dumped, which files have been dumped, but still need to be listed and/or recompiled. The functions described below comprise a coherent package for eliminating this burden from the user. They require that for each file, the first argument to prettydef be NIL and the third argument be fileCOMS, where file is the name of the file, ------------------------------------------------------------------------ 97 The file package was written by W. Teitelman. It can be disabled by setting filepkgflg to NIL. 14.52 98 e.g., prettydef[NIL;FOO;FOOCOMS]. 99 All the system functions that perform global file operations, e.g., load, loadfns, prettydef, tcompl, recompile, et al, as well as those functions that change data stored in files, e.g., editf, editv, DWIM corrections to user functions, reassignment of top-level variables, etc., interact with the file package. Some of these interactions are quite complex, such as those cases where the same function appears in several different files, or where the symbolic or compiled files reside in other directories, or were originally made under a different name, etc. Therefore, this section will not attempt to document how the file package works in each and every situation, but instead make the deliberately vague statement that it does the "right" thing with respect to keeping track of what has been changed, and what file operations need to be performed in accordance with those changes. NOTICING FILES Operations in the file package can be broken down roughly into three categories: (1) noticing files, (2) marking changes, and (3) updating files. Files are "noticed" by load and loadfns (or loadfrom, loadvars, etc.). All file operations in the file package are based on the root name of the file, i.e., the filename with version number and/or directory field removed. Noticing a file consists of adding its root name to the list filelst, and adding the property FILE, value ------------------------------------------------------------------------ 98 file can contain a suffix and/or version number, e.g., PRETTYDEF(NIL FOO.TEM;7 FOOVARS) is acceptable. The essential point is that the COMS be computable from the name of the file. 99 as opposed to "local" file operations such as those performed by print, read, setfileptr, etc. 14.53 100 101 ((fileCOMS . type)), to the property list of its root name, where type indicates how the file was loaded, e.g., completely loaded, only partially loaded as with loadfns, loaded as a compiled file, etc. For example, if the user performs load[FOO.LSP;2], FOO.LSP is added to filelst, and ((FOOCOMS . T)) is put on the property list of FOO.LSP. The property FILE is used to determine whether or not the corresponding file has been modified since the last time it was loaded or dumped as described below. In addition, the property FILECHANGES contains the union of all changes since the file was loaded (i.e., there may have been several sequences of editing and rewriting the file), and the property FILEDATES a list of version numbers and the corresponding file dates. The use and maintenance of these properties is explained below. MARKING CHANGES Whenever a function is changed, either explicitly, as with editing, or implicitly, e.g., via a DWIM correction, the function is marked as being changed by adding it to the list changedfnslst. A similar procedure is followed for variables and changedvarslst, records and changedreclst, 102 etc. Periodically, the function updatefiles is called to find which ------------------------------------------------------------------------ 100 The computation of the root name is actually based on the name of the file as indicated in the FILECREATED expression appearing at the front of the file, since this name corresponds to the name the file was originally made under. Similarly, the file package can detect that the file being noticed is a compiled file (regardless of its name), by the appearance of more than one FILECREATED expressions. In this case, each of the files mentioned in the FILECREATED expressions are noticed. For example, if the user performs BCOMPL((FOO FIE)), and subsequently loads FOO.COM, both FOO and FIE will be noticed. 101 The variable loadedfilelst contains a list of the actual names of the files as loaded by load or loadfns. For example, if the user performs LOAD[EDITA.COM;3], EDITA will be added to filelst, but EDITA.COM;3 is added to loadedfilelst. loadedfilelst is not used by the file package, it is mantained for the user's benefit. 102 Initially, the file package knows about several "prettytypes", e.g. functions, variables, records, prettydefmacros, etc. page 14.63 describes how to add additional types. 14.54 103 file(s) contain the elements that have been changed. updatefiles operates by scanning filelst and interrogating the prettycoms for each file. When (if) such files are found, the name of the element is added to the value of the property FILE for the corresponding file, and the element removed from its changedlst. Thus, after updatefiles has completed operating, the files that need to be dumped are simply those files on filelst for which cdr of their FILE property is non-NIL. For example, if the user loads the file FOO containing definitions for FOO1, FOO2, and FOO3, edits FOO2, and then calls updatefiles, getprop[FOO;FILE] will be ((FOOCOMS . T) FOO2). Functions or variables that remain on their corresponding changedlst are those for which no 104 file has been found. UPDATING FILES Whenever a file is written using makefile (described below), the functions/variables that have been changed, i.e., cdr of the FILE property, are moved to the property FILECHANGES, and cdr of the FILE 105 property is reset (rplacd) to NIL. In addition, the file is added to the list notlistedfiles and notcompiledfiles. Whenever the user lists a file using listfiles, it is removed from notlistedfiles. Similarly, whenever a file is compiled by tcompl, recompile, bcompl, or brecompile, the file is removed from notcompiledfiles. Thus at each point, the state of all files can be determined. This information is available to the user via the function files?. Similarly, the user can see whether and how each particular file has been modified (by examining the appropriate property values), dump all files that have been modified, list all files that have been dumped but not listed, recompile all files that have been dumped but not recompiled, or any combination of any or all of the above by using one of the function described below. ------------------------------------------------------------------------ 103 updatefiles is called by files?, cleanup, makefiles, and addfile, i.e., any procedure that requires the FILE property to be up to date. (The user can also invoke updatefiles directly.) This procedure is followed rather than update the FILE property after each change because scanning filelst and interrogating each prettycom can be a time-consuming process, and is not so noticeable when performed in conjunction with a large operation like loading or writing a file. 104 e.g., the user defines a new function but forgets to add it to the prettycoms for the corresponding file. For this reason, both files? and cleanup print warning messages when changedfnslst is not NIL following an updatefiles. 105 If the file was not on filelst, e.g., the user defined some functions and initialized the corresponding prettydoms without loading a file, then the file will be "noticed" by virtue of its being written. i.e., added to filelst, and given appropriate FILE, FILEDATES and FILECHANGES properties. 14.55 MAKEFILE makefile[file;options;reprintfns;sourcefile] notices file if not previously noticed. Performs linelength[filelinelength], and calls prettydef giving it NIL, file, fileCOMS, reprintfns, sourcefile, and the list of changes 106 as its arguments, restores original linelength, and then adds file to 107 notlistedfiles, notcompiledfiles. options is a list of options or a single option interpreted as follows: FAST perform prettydef with prettyflg=NIL RC call recompile after prettydef or brecompile if there are any block 108 declarations specified in fileCOMS. C calls tcompl after prettydef or bcompl if there are any block declarations specified in fileCOMS. CLISPIFY perform prettydef with clispifyprettyflg=T, causing clispify (see Section 23) to be called on each function defined as an expr before it ------------------------------------------------------------------------ 106 fileCOMS are constructed from the name field only, e.g., makefile[FOO.TEM] will work. The list of changes is simply cdr of the FILE property, as described earlier, i.e., those items that have been changed since the last makefile. prettydef merges those changes with those handled in previous calls to makefile, and stores the result on the property FILECHANGES. This list of changes is included in the FILECREATED expression printed at the beginning of the file by printdate, along with the date and version number of the file that was originally noticed, and the date and version number of the current file, i.e., this one. (these two version numbers and dates are also kept on the property FILEDATE for various integrity checks in connection with remaking a file as described below.) 107 Files that do not contain any function definitions or those that have on their property list the property FILETYPE with value DON'TCOMPILE, are not added to notcompiledfiles, nor are they compiled even when options specifies C or RC. 108 Including any generated via the COMS command or via a prettymacro. 14.56 109 is prettyprinted. NOCLISP performs prettydef with prettytranflg=T, causing CLISP translations to be printed, if any, in place of the corresponding CLISP expression, e.g., iterative statement. LIST calls listfiles on file. REMAKE 'remakes' file. See discussion below. 110 NEW does not remake file. If F, ST, STF, or S is the next item on options following C or RC, given to the compiler as the answer to the compiler's question LISTING?, e.g., makefile[FOO;(C F LIST)] will dump FOO, then tcompl or bcompl it specifying that functions are not to be redefined, and finally list the file. The user can indicate that file must be block compiled together with other files as a unit by putting a list of those files on the property list of each file under the property FILEGROUP. For example, EDIT and WEDIT are one such group, DWIM, FIX, CLISP, and DWIMIFY another. If file has a FILEGROUP property, the compiler will not be called until all files on this property have been dumped that need to be. REMAKING A SYMBOLIC FILE Most of the time that a symbolic file is written using prettydef, only some, usally a few, of the functions that it contains have been changed since the last time the file was written. A considerable savings in time is afforded by copying the prettprinted definitions of those functions that have not changed from an earlier version of the symbolic file, and ------------------------------------------------------------------------ 109 Alternatively, if file has the property FILETYPE with value CLISP, prettydef is called with clispifyprettyflg reset to CHANGES, which will cause clispify to be called on all functions marked as having been changed. For more details, see discussion of clispifyprettyflg in Section 23. Note that if file has property FILETYPE with value CLISP, the compiler will know to dwimify its functions before compiling them, as described in Sections 18 and 23. 110 If makefileremakeflg is T (its initial setting), the default for all calls to makefile is to remake. The NEW option is provided in order to override this default. 14.57 111 prettyprinting only those functions that have been changed. To this end, prettydef has two additional arguments, reprintfns and sourcefile. reprintfns can be a list of functions to be prettyprinted, or EXPRS meaning prettyprint all functions with EXPR definitions, or ALL meaning prettyprint all functions either defined as exprs or with EXPR 112 properties. sourcefile is the name of the file from which to copy the definitions for those functions that are not going to be prettyprinted, i.e., those not specified by reprintfns. sourcefile=T means use most recent version (i.e., highest number) of prttyfile, the second argument to prettydef. If sourcefile cannot be found, prettydef prints the message "file NOT FOUND, SO IT WILL BE WRITTEN ANEW", and proceeds as it does when reprintfns and sourcefile are both NIL. MAKEFILE AND REMAKING A FILE While a file can be remade by appropriately specifying the reprintfns and sourcefile arguments to prettydef, remaking is intended to be used in conjunction with makefile, which performs a number of "do-what-I-mean" type of services in this context, as described below. 113 When a makefile remake is being performed, prettydef will be called specifying as reprintfns those functions that have been changed since ------------------------------------------------------------------------ 111 Remaking a symbolic file does not depend on the earlier version having a file map, although it is considerably faster if one does exist. In the case of a remake where no file map is available, prettydef scans the file looking for the corresponding definition whenever it is about to copy the definition to the new file. The scan utilizes skread (page 14.15), and prettydef does not begin scanning from the beginning of the file each time, but instead "walks through" the original file as it is writing the new file. Since the functions are for the most part in the same order, prettydef never has to scan very far. However, prettydef also builds a map of the functions it has skipped over so that if the order of functions is reversed in the new file, prettydef is able to back up and pick up a function previously skipped. The net result is still a significant savings over (re)prettyprinting the entire file, although not as great a savings as occurs when a map is available. 112 Note that doing a remake with reprintfns=NIL makes sense if there have been changes in the file, but not to any of the functions, e.g., changes to vars or property lists. 113 The normal default for makefile is to remake, as indicated by the value of makefileremakeflg, initially T, i.e., the user does not have to explicitly include REMAKE as an option. Note that the user can override this default for particular files by using the NEW option (page 14.57). 14.58 114 the last version of the file was written. For sourcefile, makefile obtains the full name of the most recent version of the file (that it 115 knows about) from the FILEDATES property, and checks to make sure that the file still exists, and has the same file date as that stored on the FILEDATES property. If it does, makefile calls prettydef specifying 116 that file as sourcefile. In the case where the most recent version of the file cannot be found, makefile will attempt to remake using the original version of the file, i.e., the one first loaded, and specifying as reprintfns the union of all changes that have been made, which it obtains from the FILECHANGES property. If both of these fail, makefile prints the message "CAN'T FIND EITHER THE PREVIOUS VERSION OR THE ORIGINAL VERSION OF file, SO IT WILL HAVE TO BE WRITTEN ANEW", and then calls prettydef with reprintfns and sourcefile=NIL. When a remake is specified, makefile also checks the state of the file (cdar of the FILE property) to see how the file was originally loaded (page 14.53). If the file was originally loaded as a compiled file, makefile will automatically call loadvars to obtain those DECLARE: expressions that are contained on the symbolic file, but not the compiled file, and hence have not been loaded. If the file was loaded by loadfns (but not loadfrom), then loadvars will automatically be 117 called to obtain the non-DEFINEQ expressions. If a remake is not being performed, i.e., makefileremakeflg is NIL, or the option NEW was specified, makefile checks the state of the file to make sure that the entire symbolic file was actually loaded. If the file was loaded as a compiled file, makefile prints the message "CAN'T DUMP: ONLY THE COMPILED FILE HAS BEEN LOADED." Similarly, if only some of the symbolics were load via loadfns or loadfrom, makefile prints "CAN'T DUMP: ONLY SOME OF ITS SYMBOLICS HAVE BEEN LOADED." In both cases, makefile will then ask the user if it should dump anyway, and if the user declines, makefile does not call prettydef, and returns (file NOT DUMPED) as its value. ------------------------------------------------------------------------ 114 The user can specify reprintfns as the third argument to makefile. 115 The user can also specify sourcefile as the fourth argument to makefile, in which case the above checks are not executed. 116 This procedure permists the user to load or loadfrom a file in a different directory, and still be able to makefile-remake. 117 If the file has never been loaded or dumped, e.g., the user simply set up the fileCOMS himself, then makefile will never attempt to remake the file, regardless of the setting of makefileremakeflg, or whether the REMAKE option was specified, but instead will call prettydef with sourcefile=reprintfns=NIL. 14.59 makefiles[options;files]For each file on files that has been changed, performs makefile[file;options], If files=NIL, filelst is used, e.g., makefiles[LIST] will make and list all files that have been changed. In this case, if any functions (or other prettytypes) have been defined or changed and they are not contained in one of the files on filelst, makefiles calls addtofiles? to allow the user to specify where these go. The value of makefiles is a list of all files that are made. listfiles[files] nlambda, nospread function. Uses bksysbuf to load system buffer appropriately to list each file on files, (if NIL, notlistedfiles is used) followed by a QUIT command, then calls a lower EXEC via subsys (Section 21). The EXEC will then read from the system buffer, list the 118 files, and QUIT back to the program. Each file listed is removed from notlistedfiles if the listing is completed, e.g., if the user control-C's to stop the listing and QUITS. For each file not found, listfiles prints the message " NOT FOUND" and proceeds to the next file on files. compilefiles[files] nlambda, nospread function. Executes the RC option of makefile for each member of files. 119 (If files=NIL, notcompiledfiles is used.) files?[] Prints on terminal the names of those files that have been modified but not dumped, dumped but not listed, dumped but not compiled, plus the names of those functions and other prettytypes ------------------------------------------------------------------------ 118 listfiles calls the function listfiles1 on each file to be listed. listfiles1 computes the appropriate string to be fed to TENEX by concating LIST$, the file name, and the value of listfilestr, initially "C". The user can reset listfilestr to specify subcommands for the list command, or advise or redefine listfiles1 for more specialized applications. 119 If car of files is a list, it is interpreted as the options argmument to makefiles. This feature can be used to supply an answer to the compiler's LISTING? question, e.g., compilefiles[(STF)] will compile each file on notcompiledfiles so that the functions are redefined without the exprs being saved. 14.60 (if any) that are not contained in any file. If there are any, files? then calls addtofiles? to allow the user to specify where these go. cleanup[files] nlambda, nospread. Dumps, lists, and recompiles (or brecompiles) any and all files on files requiring the corresponding operation. If 120 files = NIL, filelst is used. Value is NIL. whereis[x;type;files] type is the name of a prettycom. whereis sweeps through all the files on files and returns a list of all files containing x. whereis knows about and expands all prettydef commands and prettydefmacros. type=NIL is equivalent to FNS, type=T is equivalent to VARS. Similarly, files=NIL is equivalent to (the value of) filelst, and files=T is equivalent to (APPEND FILELST SYSFILES). Note that whereis requires that the fileCOMS of the corresponding files be available. However, in INTERLISP-10, the system fileCOMS are clobbered to save space. Therefore, if the user wants to ask the location of a system function, variable, etc., he should first load the file FNS/VARS. addtofiles?[] asks the user if he wants to say where the various changed items that do not belong to any file should be placed. If user answers N(o), returns NIL without taking any action. Otherwise, maps through all the changedlst's, prints each element, and accepts one of four responses: (1) a file name or name of a list, e.g., FOO or FOOFNS. Adds the item to the corresponding file or list, using addtofile. (2) line-feed - means same as the user's previous response (3) space - take no action ------------------------------------------------------------------------ 120 The user can affect the operation of cleanup by resetting the variable cleanupoptions, initially (LIST RC). For example, if cleanupoptions is (RC F), no listing will be performed, and no functions will be redefined as the result of compiling. Alternatively, if car of files is a list, it will be interpreted as the list of options regardless of the value of cleanupoptions. 14.61 (4) ] - item is marked as a dummy item by adding it to NILCOMS, i.e., tell file package not to worry about what to do with this item. addtofile[item;file;type] adds item, of type type to file. type is a pretty type, e.g., FNS, ARRAYS, etc. file is either a file name, or name of a variable whose value is a list. Uses mergeinsert (Section 6) to insert item at the right point. Value is file. addtofile is undoable. filefnslst[file] returns a list of the functions in file, i.e., specified by fileCOMS. filefnslst knows about prettydefmacros. newfile2[name;coms;type]coms is a list of prettydef commands, type is usually FNS or VARS but may be BLOCKS, ARRAYS, etc. or the name of any other prettydef command. If name=NIL, newfile2 returns a list of all elements of type type. (filefnslst and bcompl and brecompile use this option.) If name=T, newfile2 returns T if there are any elements of type type. (makefile uses this option to determine whether the file contains any FNS, and therefore should be compiled, and if so, whether it contains any BLOCKS, to determine whether to call bcompl/brecompile or tcompl/recompile.) Otherwise, newfile2 returns T if name is "contained" in coms. (whereis uses newfile2 in this way.) If the user often employs prettydefmacros, their expansion by the various parts of the system that need to interrogate files can result in a large number of conses and garbage collections. If the user could inform the file package as to what his various prettydefmacros actually produce, this expansion would not be necessary. For example, the user may have a macro called GRAMMARS which dumps various property lists but no functions. Thus, the file package could ignore this command when seeking information about FNS. The user can supply this information by putting on the property list of the prettydef command, e.g., GRAMMARS, 121 under the property PRETTYTYPE, a function (or LAMBDA expression) of ------------------------------------------------------------------------ 121 If nothing appears on property PRETTYTYPE, the command is expanded as before. 14.62 three arguments, com, type, and name, where com is a prettydef command, and type and name corrrespond to the arguments to newfile2. The result of applying the function to these arguments should be a list of those 122 elements of type type contained in com. PRETTYTYPELST Currently, the file package knows about several different "prettytypes": functions, variables, records, etc. As described on page 14.54, whenever a function, variable, etc. is changed, newfile? (described below) is called to add it to the corresponding changedlst, e.g., changedfnslst, changedvarslst, etc. Updatefiles operates by mapping down filelst and using newfile2 to determine if the corresponding file contains any of the elements on the various changedlsts. The user can tell the file package about additional prettytypes by adding appropriate entries to prettytypelst. Each element of prettytypelst is a list of the form (name-of-changedlist type string), where string is optional. For example, prettytypelst is initially ((CHANGEDFNSLST FNS "functions") 123 (CHANGEDVARSLST VARS)). If the user adds (CHANGEDGRAMLST GRAMMARS) to prettytypelst, then updatefiles will know to move elements on changedgramlst to the FILE property for the files that contain them. The function newfile? can be used to mark elements as being changed, i.e., to move them to their respective changedlst. newfile?[name;changedlst] changedlst is the name of a changedlst, e.g., CHANGEDFNSLST, CHANGEDGRAMLST, etc. newfile? (undoably) adds name to changedlst. Value is name. newfile? is used by the editor, DWIM, define, etc. ------------------------------------------------------------------------ 122 Actually, when name=T, it is sufficient to return T if there are any elements of type type in com. Similary, when name is an atom other than T or NIL, return T if name is contained in com. Finally, if name is a list, it is sufficient to return a list of only those elements of type type contained in com that are also contained in name. The user may take advantage of these conventions of newfile2 to reduce the number of conses required for various file package operations, such as calls to whereis that editf performs when given a function without an expr (see Section 9). However, note that simply returning a list of all elements of type type found in com will always work. 123 If string is supplied, files? will inform the user if any elements remain on the changed list after updatefiles has completed. Similarly, makefiles will warn the user that some elements of this type are not going to be dumped in the event that it could not find the file to which they belonged. 14.63