{Begin SubSec Input Functions}
{Title Input Functions}
{Text

{index *BEGIN* input functions}


Most of the functions described below have an argument {arg FILE}, which specifies the name of the file on which the operation is to take place.  If {arg FILE} is {lisp NIL}, the primary input file will be used.{index primary input file}  If the file argument is a string, input will be taken from that string (and the string pointer reset accordingly).{index reading from strings}

Most input functions also have a {arg RDTBL} argument, which specifies the readtable{index readtables} to be used for input.   If {arg RDTBL} is {lisp NIL}, the primary readtable will be used.{index primary readtable}
Readtables are described on {PageRef Tag Readtables}.

Note: in all Interlisp-10 symbolic files, {index end-of-line}end-of-line is indicated by the characters {index carriage-return}carriage-return and {index line-feed}line-feed in that order.  Accordingly, on input from files, Interlisp-10 skips all line-feeds that immediately follow carriage-returns.  On input from the terminal, Interlisp echos a line-feed whenever a carriage-return is input.

When reading from the {index terminal}terminal, the input is buffered a line at a time (unless buffering has been inhibited by {lisp (CONTROL T)}, or the input is being read by {fn READC} or {fn PEEKC}) and can be backed up over using specified editing characters.  The user can erase a character at a time, the whole line, or, in Interlisp-D, a word at a time.  The keys that perform these editing functions are assignable via the {fn SETSYNTAX} function ({PageRef Fn SETSYNTAX}), with the intial settings chosen to be those most natural for the given operating system: characters are deleted one at a time by {index control-A}control-A under Tenex, Delete under Tops20, and {index BackSpace}BackSpace in Interlisp-D; the whole line is erased by {index control-Q}control-Q under Tenex and in Interlisp-D, and {index control-U}control-U under Tops20; words are erased by {index control-W}control-W in Interlisp-D.

The character-deleting action on normal terminals is to echo a {lisp \}{index \ (Printed by System)} followed by the erased character; on the Interlisp-D display the character is physically erased from the screen (this action can also be specified for display terminals in other Interlisps; see {PageRef Fn DELETECONTROL}).  The line-deleting action is normally to print {lisp ##}{index ## (Printed by System)} and start over on a new line.  Neither will back up beyond the previous carriage-return.

When reading from a file, and an end of file is encountered, all input functions close the file and generate an error, {index END OF FILE Error}{lisp END OF FILE} (unless {fn WHENCLOSE} has been used to alter this behavior; see {PageRef Fn WHENCLOSE}).


{FnDef {FnName READ} {FnArgs FILE RDTBL FLG}
{Text
Reads one expression from {arg FILE}.  Atoms are delimited by the break and separator characters as defined in {arg RDTBL}.  To include a break or separator character in an atom, the character must be preceded by the input escape character{index *PRIMARY* escape character} {lisp %},{index *PRIMARY* % (escape character)} e.g., {lisp AB%(C} is the atom {lisp AB(C}, {lisp %%} is the atom {lisp %}, {lisp %}{it control-A} is the atom control-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{index control-V}, e.g., {lisp ↑VC} for control-C.

Strings{index strings} are delimited by double quotes.{index "}  To input a string containing a double quote or a %, precede it by %,{index % (escape character)} e.g., {lisp "AB%"C"} is the string {lisp AB"C}.  Note that % can always be typed even if next character is not "special", e.g., {lisp %A%B%C} is read as {lisp ABC}.

If an atom is interpretable as a number, {index READ FN}{fn READ} creates a number, e.g., {lisp 1E3}{index E (in a floating point number)} reads as a floating point number,{index floating point numbers} {lisp 1D3} as a literal atom, {lisp 1.0} as a number, {lisp 1,0} as a literal atom,{index literal atoms} etc.  An integer can be input in {index *PRIMARY* octal}octal by terminating it with a {lisp Q},{index *PRIMARY* Q (following a number)} e.g., {lisp 17Q} and {lisp 15} read in as the same integer.  The setting of {index RADIX FN}{fn RADIX} ({PageRef Fn RADIX}) determines in which base integers are printed.

When reading from the {index terminal}terminal, all input is line-buffered{index line-buffering} to enable the action of the backspacing control characters (unless inhibited by {index CONTROL FN}{lisp (CONTROL T)} ({PageRef Fn CONTROL})).  Thus no characters are actually seen by the program until a carriage-return{index carriage-return} is typed.{foot
Actually, the line buffering is terminated by the character with terminal syntax class {lisp EOL} (see {PageRef Tag SyntaxClass}), which in most cases is carriage-return.
}{comment endfootnote}
However, for reading by {fn READ}, when a matching right parenthesis is encountered,{index *PRIMARY* parentheses counting by READ} the effect
is the same as though a carriage-return were typed, i.e., the characters are transmitted.{foot
The line buffer is also transmitted to {fn READ} whenever an {lisp IMMEDIATE} read-macro character is typed ({PageRef Tag ReadMacros}).
}{comment endfootnote}
To indicate this, Interlisp also prints a carriage-return line-feed on the terminal.


In Interlisp-10, the character control-W is defined as an {lisp IMMEDIATE} read macro that erases the last expression read, echoing a {lisp \\} and the erased expression, e.g., {lisp (NOW IS THE TIME↑W \\ TIME)} returns {lisp (NOW IS THE)}.{index *PRIMARY* control-W}{index *PRIMARY* \\ (Printed by System)}
Control-W can be used repeatedly, and can also back up and erase expressions on previous lines.  However, since control-W is implemented as an {lisp IMMEDIATE} read-macro character, ({PageRef Tag ReadMacros}), once it is typed, then individual {it characters} typed before it cannot be deleted by control-A or control-Q, since they will already have passed through the line buffer.

In Interlisp-D, control-W is instead defined as an editing character that deletes the last "word" of input, i.e., back to the first non-{lisp OTHER} character preceding the first non-{lisp SEPR} character, essentially a repeated BackSpace.  The character performing this function is assignable using the {lisp WORDDELETE} syntax ({PageRef fn SETSYNTAX}).


{arg FLG}={lisp T} suppresses the carriage-return normally typed by {fn READ} following a matching right parenthesis.  (However, the characters are still given to {fn READ}; i.e., the user does not have to type the carriage-return.)
{note a peculiar feature--bvm}

}}{comment endfndef READ}




{FnDef {FnName RATOM} {FnArgs FILE RDTBL}
{Text
Reads in one atom from {arg FILE}.  Separation of atoms is defined by {arg RDTBL}.  {lisp %}{index % (escape character)} is also an escape character for {fn RATOM}, and the remarks concerning line-buffering{index line-buffering} and editing control characters also apply.

If the characters comprising the atom would normally be interpreted as a number by {fn READ}, {index numbers}that number is returned by {fn RATOM}.  Note however that {fn RATOM} takes no special action for {lisp "}{index "} whether or not it is a break character, i.e., {index RATOM FN}{fn RATOM} never makes a string.
}}


{FnDef {FnName RSTRING} {FnArgs FILE RDTBL}
{Text
Reads characters from {arg FILE} up to, but not including, the next break or separator
character, and returns them as a string.  Control-A, control-Q, control-V, and {lisp %} have the same effect as with {fn READ}.
}}


{index *BEGIN* break characters}
{index *BEGIN* separator characters}


Note that the break or separator character that terminates a call to {index RATOM FN}{fn RATOM}
or {index RSTRING FN}{fn RSTRING} is {emphasize not} read by that call, but remains in the buffer to become the first character seen by the next reading function that is called.  If that function is {fn RSTRING}, it will return the null string.  This is a common source of program bugs.



{FnDef {FnName RATOMS} {FnArgs A FILE RDTBL}
{Text
Calls {fn RATOM} repeatedly until the atom {arg A} is read.  Returns a list of the atoms read, not including {arg A}.
}}


{FnDef {FnName RATEST} {FnArgs FLG}
{Text
If {arg FLG} = {lisp T}, {fn RATEST} returns {lisp T} if a separator was encountered immediately prior to the atom returned by the last {fn RATOM} or {fn READ}, {lisp NIL} otherwise.

If {arg FLG} = {lisp NIL}, {fn RATEST} returns {lisp T} if last atom read by {fn RATOM} or {fn READ} was a break character, {lisp NIL} otherwise.

If {arg FLG} = {lisp 1}, {fn RATEST} returns {lisp T} if last atom read (by {fn READ} or {fn RATOM}) contained a {lisp %} (as an escape character, e.g., {lisp %[} or {lisp %A%B%C}), {lisp NIL} otherwise.

{note Does anyone ever use this bizarre function?  --bvm}
}}


{FnDef {FnName READC} {FnArgs FILE RDTBL}
{Text
Reads and returns the next character, including {lisp %}, {index % (escape character)} {lisp "},{index "} etc, i.e., is not affected by break, separator, or escape character.  The action of {fn READC} is subject to line-buffering, i.e., {fn READC} does not return a value until the line has been terminated even if a character has been typed.  Thus, the editing control characters have their usual effect.  {arg RDTBL} does not directly affect the value returned, but is used as usual in line-buffering, e.g., determining when input has been terminated.  If {index CONTROL FN}{lisp (CONTROL T)} has been executed ({PageRef Fn CONTROL}), defeating line-buffering,{index line-buffering} the {arg RDTBL} argument is irrelevant, and {fn READC} returns a value as soon as a character is typed (even if the character typed is one of the editing characters, which ordinarily would never be seen in the input buffer).
}}


{FnDef {FnName PEEKC} {FnArgs FILE FLG}
{Text
Returns the next character, but does not actually read it and remove it from
the buffer.  If {arg FLG}={lisp NIL}, {fn PEEKC} is not subject to line-buffering{index line-buffering},{foot
If reading from the terminal, the character is echoed as soon as {fn PEEKC} reads it, even though it is then "put back" into the system buffer, where a subsequent del{index del} (or control-Z on TOPS-20{index control-Z (TOPS-20) Term}) before the character is read can clear it, and where subsequent line buffer backspacing could change it.  Thus it is possible for the value returned by {fn PEEKC} to "disagree" in the first character with a subsequent {fn READ}.
}{comment endfootnote}
i.e., it returns a value as soon as a character has been typed.
Otherwise, {index PEEKC FN}{fn 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.

{note It appears that the second arg to PEEKC is ignored in Interlisp-D --bvm}
}}

{FnDef {FnName SKIPSEPRS} {FnArgs FILE RDTBL}
{Text
Skips over characters in {arg FILE} that are separators in {arg RDTBL}, stopping when the first non-separator is encountered.  This character is returned as the value of {fn SKIPSEPRS}, but it is not read so that it will be seen by the next input operation.  Value is {lisp NIL} and {arg FILE} is left positioned at its end if no non-separators remain.
}}



{FnDef {FnName LASTC} {FnArgs FILE}
{Text
Returns the last character read from {arg FILE}.
}}


{index *END* break characters}
{index *END* separator characters}


{fn READ}, {fn RATOM}, {fn RATOMS}, {fn PEEKC}, {fn READC} all wait for input if there is none. The only way to test whether or not there is input is to use {fn READP}:


{FnDef {FnName READP} {FnArgs FILE FLG}
{Text
Returns {lisp T} if there is anything in the input buffer{index input buffer} of {arg FILE}, {lisp NIL} otherwise.  Note that because of line-buffering,{index line-buffering} {fn READP} may return {lisp T}, indicating there is input in the buffer, but {fn READ} may still have to wait.

{note the following is an awful crock that we may want to fix or tone down some --bvm}

Frequently, the terminal's input buffer contains a single {lisp 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 {lisp (READP T)} returns {lisp NIL} in this case.  However, if {arg FLG}={lisp T}, {fn READP} also returns {lisp T} in this case, i.e., {lisp (READP T T)} returns {lisp T} if there is {it any} character in the input buffer.
}}


{FnDef {FnName WAITFORINPUT} {FnArgs FILE}
{Text
Waits until input is available from {arg FILE} or from the terminal, i.e. from {lisp T}.  {fn WAITFORINPUT} is functionally equivalent to {lisp (until (OR (READP T) (READP FILE)) do NIL)}, except that it does not use up machine cycles while waiting.  Returns the device for which input is now available, i.e. {arg FILE} or {lisp T}.

{arg FILE} can also be an integer, in which case {fn WAITFORINPUT} waits until there is input available from the terminal, or until {arg FILE} milliseconds have elapsed. Value is {lisp T} if input is now available, {lisp NIL} in the case that {fn WAITFORINPUT} timed out.

In Interlisp-10, {fn WAITFORINPUT} operates by dismissing, checking for available input, and then, if there is none, dismissing again, each time for an increasingly larger interval.  The initial interval is {var DISMISSINIT}{index DISMISSINIT Var} milliseconds (initially 500), and the interval grows by 1/16 for each dismissal, up to a maximum of {var DISMISSMAX}{index DISMISSMAX Var} milliseconds (initially 10,000).
}}


{note READLINE moved to Programmer's Assistant chapter}


{note {fn SKREAD} was written by J. W. Goodwin.}

{FnDef {FnName SKREAD} {FnArgs FILE REREADSTRING}
{Text
"Skip Read".  It moves the file pointer for {arg FILE} ahead as if one call to {fn READ} had been performed, without paying the storage and compute cost to really read in the structure.  {arg REREADSTRING} is for the case where the user has already performed some {fn READC}'s and {fn RATOM}'s before deciding to skip this expression.  In this case, {arg REREADSTRING} should be the material already read (as a string), and {fn SKREAD} operates as though it had seen that material first, thus setting up its parenthesis count, double-quote count, etc.

{fn SKREAD} always uses {var FILERDTBL}{index FILERDTBL Var} for its readtable.  {fn SKREAD} may have difficulties if unusual read-macros have been added to {var FILERDTBL}.  {fn SKREAD} will not recognize read-macro characters in {arg REREADSTRING}, nor {lisp SPLICE} or {lisp INFIX} read macros.  This is only a problem if the read-macros are defined to parse subsequent input in the file which does not follow the normal parenthesis and string-quote conventions in {var FILERDTBL}.

{fn SKREAD} returns {lisp %)} if the read terminated on an unbalanced closing parenthesis; {lisp %]} if the read terminated on an unbalanced {lisp %]}, i.e., one which also would have closed any extant open left parentheses; otherwise {lisp NIL}.
}}


{FnDef {FnName SKIPSEPRS} {FnArgs FILE RDTBL}
{Text
Advances the file pointer for {arg FILE} until it encounters a non-separator character (as defined by {arg RDTBL}).  The file pointer is left positioned ready to read the character, which is also returned.  If no non-separator character is found before the end of file is reached, {fn SKIPSEPRS} returns {lisp NIL} and leaves the pointer positioned at the end of the file.  Useful for skipping over "white space" when scanning a file character by character. 
}}


{index *END* input functions}


}{End SubSec Input Functions}