Google
 

Trailing-Edge - PDP-10 Archives - decus_20tap1_198111 - decus/20-0004/14lisp.doc
There are no other files named 14lisp.doc in the archive.











                               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]=<TEITELMAN>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[<TEITELMAN>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[<NEWLISP>EDITA.COM;3], EDITA will be added to filelst,
    but <NEWLISP>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 "<file-name> 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 <LISP>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