{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}