mirror of
https://github.com/PDP-10/its.git
synced 2026-01-11 23:53:12 +00:00
343 lines
13 KiB
Plaintext
Executable File
343 lines
13 KiB
Plaintext
Executable File
I) Introduction.
|
||
|
||
There are many instances when a MacLISP programmer wishes to
|
||
simulate an arbitrary I/O device. That is, he wishes to use the primitives
|
||
provided in LISP for doing I/O (such as READ and PRINT) yet wishes the
|
||
target/source of the characters to be completely arbitrary. I propose a
|
||
mechanism called an "SFA" (Software File Array) to handle this situation.
|
||
|
||
An SFA consists of a function and some associated local storage
|
||
bound up in an "SFA-object". In order to satisfy the above goals, an
|
||
SFA-object may be used in almost all places that a file-object can be used.
|
||
Note that the existence of SFAs will not obviate the need for the current
|
||
NEWIO implementation of files. SFAs are strictly a user entity, and the
|
||
files are still needed in order to communicate with the operating system.
|
||
|
||
The SFA-function is a user-defined EXPR/SUBR which accepts 3
|
||
arguments. Its first argument is the SFA-object on which it is to act, and
|
||
the second argument is a symbol indicating the operation to be performed.
|
||
The third argument is operation specific. The SFA-object needs to be
|
||
supplied to the function because one SFA-function may be associated with
|
||
many different SFA-objects. There are some operations used by the system
|
||
(TYI, TYO, etc...). The user is free to define new operations and to use
|
||
them by calling the SFA directly.
|
||
|
||
As there are predefined uses for many of the system I/O functions
|
||
that currently exist, when these functions are translated to SFA operations
|
||
they must retain the semantics they have when applied to file-objects.
|
||
Since this is the case, any SFA that expects to interface directly to the
|
||
standard I/O routines must know about the difference between binary and
|
||
character-oriented operations. Generally, an SFA will only handle one type
|
||
of I/O (i.e. most SFAs will not handle both the IN and TYI operation), yet
|
||
the structure of SFAs will not preclude them handling both.
|
||
|
||
|
||
II) System defined operations
|
||
|
||
1) Operations applicable to both input and output SFAs
|
||
|
||
A) WHICH-OPERATIONS
|
||
|
||
The SFA must return a list of operations which it can perform.
|
||
Every SFA *must* handle the WHICH-OPERATIONS operation.
|
||
|
||
B) OPEN
|
||
|
||
This operation is invoked if an OPEN is done with a SFA as its first
|
||
argument. The SFA should return either a file-object or a
|
||
SFA-object. The third argument to the SFA is the second argument to
|
||
the OPEN, and it defaults to NIL.
|
||
|
||
|
||
C) CLOSE
|
||
|
||
This operation is invoked when a CLOSE is done with a SFA as its
|
||
argument. There is never a third arg, and the SFA should return either
|
||
T if the close was successful and NIL if not (e.g. if the SFA was already
|
||
"closed".)
|
||
|
||
|
||
D) DELETEF
|
||
|
||
No arguments will be passed to the SFA. There is no clear global
|
||
semantic meaning of this.
|
||
|
||
|
||
E) FILEPOS
|
||
|
||
If an argument is given to FILEPOS, it is NCONS'ed and handed to the
|
||
SFA, else the SFA is given NIL. For a NIL argument, a fixnum should be
|
||
returned. For one argument, the SFA should interpret the argument as a
|
||
"position" to set the "file" to, and perform appropriate actions.
|
||
|
||
|
||
F) (STATUS FILEMODE) [operation: FILEMODE]
|
||
|
||
The SFA should return a list of adjectives describing itself. If the
|
||
SFA cannot support the FILEMODE operation (as determined by a
|
||
system-performed WHICH-OPERATIONS check), then a list of the form:
|
||
|
||
((SFA) {results of a WHICH-OPERATIONS call})
|
||
|
||
is returned.
|
||
|
||
2) Functions applicable to SFAs which can do input
|
||
|
||
If the SFA is to support normal LISP reading other than TYI, it must
|
||
support at least TYI and UNTYI, and preferably TYIPEEK also.
|
||
|
||
A) TYI
|
||
|
||
The SFA should return a fixnum representing a character. This operation
|
||
may be called from a READ, READLINE, or a straight TYI (the SFA cannot
|
||
depend upon being able to determine the context). The argument is the
|
||
value to return when EOF is reached (this is true for all input functions
|
||
including IN).
|
||
|
||
|
||
B) UNTYI
|
||
|
||
The SFA should put the argument into its input stream and on the next
|
||
TYI should spew forth the saved character rather than the next one in the
|
||
"stream". Note that an arbitrary number of UNTYI's may be done in a row.
|
||
|
||
|
||
C) TYIPEEK
|
||
|
||
The SFA should return a fixnum (as in TYI) but should not remove the
|
||
character from the input flow. Therefore, subsequent TYIPEEK's will read
|
||
the same character. If the SFA cannot handle TYIPEEK, it will be simulated
|
||
by a TYI/UNTYI pair of operations.
|
||
|
||
|
||
D) IN
|
||
|
||
The value returned should be a fixnum that is the next binary value in
|
||
the input stream. The argument is the EOF value.
|
||
|
||
|
||
E) READLINE
|
||
|
||
The value returned should be a symbol that represents one "line" of the
|
||
input stream. If the SFA cannot handle this operation, it is simulated in
|
||
terms of TYI. The argument is the value to return upon EOF.
|
||
|
||
|
||
F) READ
|
||
|
||
The value returned should be the next "object" in the input stream If
|
||
the SFA cannot handle this operation, it is simulated in terms of
|
||
TYI/UNTYI. The argument is the value to return upon EOF.
|
||
|
||
|
||
G) LISTEN
|
||
CLEAR-INPUT
|
||
|
||
For LISTEN, the total number of items (or "characters") currently
|
||
held in the input buffer is returned; for CLEAR-INPUT, the input buffer
|
||
is just thrown away.
|
||
|
||
3) Functions applicable to SFAs which can do output
|
||
|
||
A) TYO
|
||
|
||
The argument is a fixnum representing a character. The value returned
|
||
should be T if the SFA succeeds, and NIL if the output was unsuccessful.
|
||
|
||
|
||
B) OUT
|
||
|
||
The argument is a fixnum and is output as such. The TYO/OUT pair of
|
||
functions is the analog to the TYI/IN pair.
|
||
|
||
|
||
C) FORCE-OUTPUT
|
||
CLEAR-OUTPUT
|
||
|
||
For FORCE-OUTPUT, the SFA should empty its output buffer to the logical
|
||
"device" to which it is connected; for CLEAR-OUTPUT, any buffer is just
|
||
thrown away.
|
||
|
||
D) PRIN1
|
||
|
||
The SFA should print the arg in its slashified form. If the SFA
|
||
cannot perform this operation, it is simulated in terms of TYO.
|
||
|
||
|
||
E) PRINT
|
||
|
||
The SFA should print the arg in its slashified form preceeded by a
|
||
<NEWLINE> and terminated by a <SPACE>. If the SFA cannot perform this
|
||
operation, it is simulated in terms of TYO.
|
||
|
||
|
||
F) PRINC
|
||
|
||
The SFA should print the arg in its unslashified form. If the SFA
|
||
cannot perform this operation, it is simulated in terms of TYO.
|
||
|
||
|
||
G) CURSORPOS
|
||
|
||
The SFA will receive a list of the data args given to CURSORPOS. There
|
||
may be 0, 1 or 2 of these. If given the horizontal and vertical position,
|
||
there will be two elements in the list (<Vertical> <Horizontal>) which are
|
||
zero-indexed fixnums (or NIL for either/both meaning use the current value).
|
||
If given a single ascii character object, a relative cursor movement will
|
||
be expected (eg, C=Clear Screen, U=Move Up, ... [See .INFO.;LISP CURSOR])
|
||
If an empty data list is received, the SFA-handler should return the current
|
||
cursor position as a dotted pair (<Vertical> . <Horizontal>). There is
|
||
no clear global semantic meaning of this operations when
|
||
performed on non-tty's.
|
||
|
||
|
||
H) RUBOUT
|
||
|
||
The sfa should try to delete the last character output (either
|
||
by main output, or by echo output). See documentation on the MacLISP
|
||
RUBOUT function.
|
||
|
||
|
||
III) System functions for manipulating SFAs
|
||
|
||
A) (SFA-CREATE <old-SFA or SFA-function>
|
||
<amount-of-local-user-storage>
|
||
<printed-representation>)
|
||
|
||
SFA-CREATE returns an SFA-object which represents a function and
|
||
associated local storage. If the first arg is a SYMBOL, then that symbol
|
||
is taken as the SFA-function; if the first arg is an SFA-object, then the
|
||
function associated with it is used as the SFA-function, and the local
|
||
storage is possibly reclaimed (the first arg being an SFA is not yet
|
||
implemented). The second arg to this function should be the number of user
|
||
locations to allocate in the SFA-object.
|
||
|
||
When the SFA-CREATE is done, the SFA is immediatly invoked with a
|
||
WHICH-OPERATIONS call. A mask is then created corresponding to the
|
||
internal functions that the SFA knows how to do. This mask is used for
|
||
fast error-checking when a predefined operation is handed an SFA (e.g.
|
||
TYO).
|
||
|
||
|
||
B) (SFA-CALL <SFA-object> <operation> [<argument to SFA>])
|
||
|
||
SFA-CALL is used to perform an arbitrary operation on an arbitrary
|
||
SFA-object. For example, (TYO 1 <SFA>) is equivalent to
|
||
(SFA-CALL <SFA> 'TYO 1).
|
||
|
||
|
||
C) (SFAP <lisp-object>)
|
||
|
||
Returns T iff <lisp-object> is a SFA-object else returns NIL.
|
||
|
||
|
||
D) (SFA-GET <SFA-object> <fixnum or system-location-name>)
|
||
|
||
SFA-GET reads the local storage of <SFA-object>. If the second
|
||
arg is a fixnum, then location <fixnum> of the user's local storage is
|
||
accessed. This number may range from 0 to the maximum as specified when
|
||
the SFA-object is created {see SFA-CREATE}. If the second arg is a
|
||
symbol, then one of the "named" locations is accessed. The names are as
|
||
follows:
|
||
|
||
FUNCTION The SFA-function
|
||
WHICH-OPERATIONS A list of operations of interest to the
|
||
system that the SFA can perform. This is a
|
||
subset of the SFAs WHICH-OPERATIONS list.
|
||
PNAME The object to print as the "name" of an SFA
|
||
PLIST A general property list, for use by the user.
|
||
XCONS A "correspondent" for a bi-directional SFA;
|
||
akin to the TTYCONS concept for TTY's.
|
||
|
||
E) (SFA-STORE <SFA-object> <fixnum or system-location-name> <value>)
|
||
|
||
<value> is stored in the location specified by the second arg to
|
||
SFA-STORE. Locations are as for SFA-GET. It is strongly recommended that
|
||
the SFA-function NEVER be changed.
|
||
|
||
|
||
|
||
|
||
IV) Higher level tools.
|
||
|
||
A) DEFSFA -- Define a SFA
|
||
|
||
[requires some runtime support, which will be autoloaded in]
|
||
|
||
(DEFSFA <sfa-name> (<self-var> <op-var>) <slot-specs> <options>
|
||
&rest <clauses>)
|
||
|
||
<sfa-name> -- The name of this type of SFA.
|
||
|
||
<self-var> -- a variable to be bound to the SFA itself when it is sent a
|
||
message
|
||
|
||
<op-var> -- a variable to be bound to the name of the message.
|
||
|
||
<slot-specs> -- a list of slot names, or (<slot-name> <initial-value>)
|
||
each slot will have an accessor macro defined for it, with a name formed by
|
||
(SYMBOLCONC <sfa-name> '- <slot-name>)
|
||
|
||
<options> -- a list of option specs. An option spec is either a bare
|
||
symbol, denoting that the specified option is TRUE, or a list of an option
|
||
name and a value. The only option defined currently is :INIT, which
|
||
suppresses newly consed SFA's of this type getting a :INIT message if no
|
||
initial values are supplied. (If initial values are supplied, the :INIT
|
||
message must be sent in order to store them).
|
||
|
||
<clauses> -- a list of clauses. Each clause has the form
|
||
(<op or list of ops> <argspec> . <body>)
|
||
<op or list of ops> -- the ops are message keys, ala the second argument
|
||
to SEND or SFA-CALL.
|
||
<argspec> -- This is either a symbol, in which case it is bound to the
|
||
3rd argument, or a list of two or more symbols, in which
|
||
case it is bound to the 3rd-<n+2>th arguments. No error
|
||
checking on number of arguments will be done. If the symbol
|
||
is atomic, it will be reachable via either SFA-CALL or SEND,
|
||
otherwise it will be reachable only by SEND. This is
|
||
because SFA-CALL does not allow other than 3 arguments to be
|
||
passed.
|
||
<body> -- list of forms to be evaluated. The last one's value will be
|
||
returned.
|
||
|
||
This defines accessor macros for each slot in the SFA, plus a macro for
|
||
creating the SFA, named by prepending CONS-A- to the sfa-name. The
|
||
CONS-A-mumble macro does the SFA-CREATE, and immediately sends it a :INIT
|
||
message with a list of alternating slot-names and values.
|
||
|
||
All this works via the following lower-level mechanisms:
|
||
|
||
B) (SFA-UNCLAIMED-MESSAGE <sfa> <operation> <data>) Basically, this reports
|
||
the error. But first, it handles several special cases. The first is
|
||
turning a SEND into an SFA-CALL. When a SEND is performed on a SFA, it is
|
||
simulated by doing an SFA-CALL with an operation of :SEND, and a 3rd
|
||
argument of (LIST <old operation> <3rd argument> ... <nth argument>). If
|
||
:SEND is the operation to SFA-UNCLAIMED-MESSAGE, AND the SFA claims to
|
||
implement the <old operation> (in response to a WHICH-OPERATIONS-INTERNAL
|
||
query), it will turn it back into an SFA-CALL of the <old operation>, with
|
||
any extra arguments being thrown away. If it DOESN'T claim to handle it
|
||
the message is passed off to the superclass via SEND-AS
|
||
|
||
A subcase of the :SEND case is when the <old operation> is
|
||
WHICH-OPERATIONS. This implies a (SEND <sfa> 'WHICH-OPERATIONS) was done.
|
||
So this is simulated by mergeing any operations obtainable from the
|
||
superclass of SFA-CLASS. (If the EXTEND package isn't loaded, it doesn't
|
||
try to get them though.)
|
||
|
||
If the message is WHICH-OPERATIONS-INTERNAL, then the handler did not
|
||
implement WHICH-OPERATIONS-INTERNAL. We assume WHICH-OPERATIONS will
|
||
do the job and SFA-CALL that.
|
||
|
||
If the message is something other than :SEND, it just passes the message on
|
||
up to the superclass with SEND-AS.
|
||
|
||
It is recommended that any SFA's which for one reason or another do not use
|
||
DEFSFA should use SFA-UNCLAIMED-MESSAGE. Essentially the correct behaviour
|
||
with respect to SEND should result.
|
||
|
||
;;; Local modes: !
|
||
;;; Mode: Text !
|
||
;;; Auto fill mode:1 !
|
||
;;; Fill column:75 !
|
||
;;; End: !
|