CommanderOps.mesa
Copyright Ó 1989, 1991 by Xerox Corporation. All rights reserved.
Michael Plass, November 21, 1989 9:18:30 am PST
The CommanderOps is a simple stream-oriented command-line processor. This interface exports a programmer's interface to the CommanderOps and provides some facilities for managing command lines.
Intended as a simplified replacement for L. Stewart's CommandTool.
DIRECTORY
Commander USING [Handle],
IO USING [STREAM],
Rope USING [ROPE];
CommanderOps: CEDAR DEFINITIONS = BEGIN
Types and Signals
ROPE: PRIVATE TYPE = Rope.ROPE;
ArgumentVector: TYPE = REF ArgHandleObject;
An ArgumentVector is a processed command line. It stands for "argument vector" for historical reasons. When arg: ArgumentVector, arg[0] is the command, arg[1] is the first argument, and arg[arg.argc-1] is last argument.
ArgHandleObject: TYPE = RECORD [s: SEQUENCE argc: NAT OF ROPE];
Failed: ERROR [errorMsg: ROPE];
Failed may be raised by the procedures below for reasons like mis-matched double-quotes on the command line. The errorMsg gives a user-intelligible reason.
ERROR Failed may also raised by CommandProcs, instead of returning [result: $Failed, msg: "..."]. This will be caught and converted into a failed command, so most of the times the CommandProcs don't need to catch Failed.
Procedures for Processing Command Lines
The following procedures are usefully called by CommandProcs right after they get control.
QuoteTreatment: TYPE ~ {stripQuotes, leaveQuotes};
ParseToList: PROC [cmd: Commander.Handle, quoteTreatment: QuoteTreatment ¬ stripQuotes] RETURNS [list: LIST OF ROPE, length: NAT];
! Failed;
ParseToList breaks up cmd.commandLine into a list of tokens. Tokens are generally separated by whitespace, but a "double-quoted string" is a single token.
Parse: PROC [cmd: Commander.Handle, quoteTreatment: QuoteTreatment ¬ stripQuotes] RETURNS [argv: ArgumentVector];
! Failed;
Parse does the same job as ParseToList, but returns a sequence of tokens. In accordance with historical precedent, cmd.command is returned as argv[0] and the "real" arguments start at argv[1].
NumArgs: PROC [cmd: Commander.Handle] RETURNS [INT];
Returns number of argument tokens that would be produced by CommanderOps.Parse (including the name of the command itself). This is cmd.argv.argc.
NextArgument: PROC [cmd: Commander.Handle, quoteTreatment: QuoteTreatment ¬ stripQuotes] RETURNS [ROPE];
Returns the next command line token. ArgN sets the "pointer". The initial value of the pointer is the first token after the name of the command. Returns NIL after returning the last real argument.
ArgN: PROC [cmd: Commander.Handle, n: INT, quoteTreatment: QuoteTreatment ¬ stripQuotes] RETURNS [ROPE];
Returns the nth command line argument. ArgN[cmd, 0] is the name of the command. After any given ArgN, NextArgument will return the (n+1)st argument. Returns NIL if there is no nth argument.
Token: TYPE ~ RECORD [value, literal: ROPE, start: INT];
nullToken: Token ~ [NIL, NIL, 0];
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [Token];
For clients that need to parse tokens off a stream, using the same conventions as the above parsing routines. The stream must support GetIndex and SetIndex.
Returns nullToken on end-of-stream
token.value has quotation marks stripped
token.literal has quotation marks intact
token.start is the index (via IO.GetIndex) of the start of the token
Procedures for Executing commands
DoCommand: PROC [commandLine: ROPE, parent: Commander.Handle] RETURNS [result: REF];
Execute the given commandLine. Parent will be used to provide streams and the property list. cmd.command and cmd.commandLine will be overwritten. This is particularly useful for commands which wish to execute their own command lines as commands: DoCommand[cmd.commandLine, cmd]; Result is the result returned by the command.
DoCommandRope: PROC [commandLine, in: ROPE ¬ NIL, parent: Commander.Handle]
RETURNS [out: ROPE, result: REF];
Execute the given commandLine. (The command name must be the first token on the commandLine). The in, out, and err streams connected to the corresponding ropes. The property list and error streams come from parent. If parent is defaulted NIL, then a standard property list will be created and error output will be directed to out along with standard output. Result is the result returned by the command.
ExecuteCommand: PROC [cmd: Commander.Handle, wholeCommandLine: ROPE]
RETURNS [result: REF, msg: ROPE];
Execute the given wholeCommandLine. cmd must be a valid commander handle.
Commander Properties
These maintain cmd.propertyList, using mutable semantics.
PutProp: PROC [cmd: Commander.Handle, key, val: REF];
GetProp: PROC [cmd: Commander.Handle, key: REF] RETURNS [REF];
Creation/ReadEvalPrint
CreateFromStreams: PROC [in, out, err: IO.STREAM ¬ NIL, parentCommander: Commander.Handle ¬ NIL] RETURNS [cmd: Commander.Handle];
ReadEvalPrintLoop: PROC [cmd: Commander.Handle] RETURNS [hadFailure: BOOL];
Here is an example that ought to work in the Viewers world to create a new command tool:
CreateCommandToolViewer: PROC = {
in, out: IO.STREAM;
[in: in, out: out] ← ViewerIO.CreateViewerStreams[name: "CommanderOps"];
TRUSTED {Process.Detach[FORK ReadEvalPrintLoop[CreateFromStreams[in: in, out: out]]]};
};
Clients that need to do more may refer to CommanderBackdoor.
END.