PipeFittingImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by Peter Kessler, December 19, 1985 2:51:58 pm PST
DIRECTORY
Commander USING [CommandProc, Register],
CommandTool USING [Failed, ParseToList],
FileNames USING [ResolveRelativePath],
FS USING [Error, ErrorDesc, StreamOpen],
IO USING [Close, EndOf, EndOfStream, Error, GetBlock, PutBlock, STREAM],
Process USING [CheckForAbort],
Rope USING [Cat, Concat, Equal, ROPE],
Cat,
Tee;
PipeFittingImpl: CEDAR PROGRAM
IMPORTS Commander, CommandTool, FileNames, FS, IO, Process, Rope
EXPORTS Cat, Tee
= {
FromNames: PUBLIC PROCEDURE [in: IO.STREAM, nameList: LIST OF Rope.ROPE, out: IO.STREAM]
RETURNS [result: REFNIL, msg: Rope.ROPENIL] = {
FSErrorMsg: PROC [error: FS.ErrorDesc] RETURNS [Rope.ROPE] = {
SELECT error.group FROM
lock => RETURN[" -- locked!\n"];
ENDCASE =>
IF error.code = $unknownFile
THEN RETURN [" -- not found!\n"]
ELSE RETURN[Rope.Cat[" -- FS.Error: ", error.explanation, "\n"]];
};
streamList: LIST OF IO.STREAMNIL;
IF nameList # NIL THEN {
FOR left: LIST OF Rope.ROPE ← nameList, left.rest WHILE left # NIL DO
IF Rope.Equal[left.first, "-"]
THEN {
streamList ← CONS[in, streamList];
}
ELSE {
fileStream: IO.STREAM
FS.StreamOpen[FileNames.ResolveRelativePath[left.first] !
FS.Error =>
IF error.group # $bug THEN {
msg ← Rope.Concat[left.first, FSErrorMsg[error]]; GO TO Die
}];
streamList ← CONS[fileStream, streamList];
}
ENDLOOP;
[result, msg] ← FromStreams[streamList: streamList, out: out];
FOR left: LIST OF IO.STREAM ← streamList, left.rest WHILE left # NIL DO
IF left.first # NIL AND left.first # in THEN IO.Close[left.first];
ENDLOOP;
}
EXITS
Die => result ← $Failure;
};
FromStreams: PUBLIC PROCEDURE [streamList: LIST OF IO.STREAM, out: IO.STREAM]
RETURNS [result: REFNIL, msg: Rope.ROPENIL] = {
nBytesRead: NAT ← 0;
block: REF TEXTNEW[TEXT[256]];
FOR left: LIST OF IO.STREAM ← streamList, left.rest WHILE left # NIL DO
WHILE NOT IO.EndOf[left.first] DO
block.length ← block.maxLength;
nBytesRead ← IO.GetBlock[left.first, block, 0, block.maxLength !
IO.EndOfStream => EXIT;
IO.Error => EXIT;
];
IO.PutBlock[out, block, 0, nBytesRead !
IO.EndOfStream => EXIT;
IO.Error => EXIT;];
Process.CheckForAbort[];
ENDLOOP;
ENDLOOP;
};
CatCommand: Commander.CommandProc = {
[cmd: REF CommandObject] RETURNS [result: REFNIL, msg: ROPENIL]
CommandObject = [
in, out, err: IO.STREAM, commandLine, command: ROPE,
propertyList: List.AList, procData: CommandProcHandle]
arglist: LIST OF Rope.ROPE;
argc: NAT;
[arglist, argc] ← CommandTool.ParseToList[cmd, TRUE
! CommandTool.Failed => {msg ← errorMsg; GO TO Die}];
IF arglist = NIL
THEN {
msg ← "Usage: Cat [filename | -] ...";
}
ELSE {
[result, msg] ← FromNames[cmd^.in, arglist, cmd^.out];
};
EXITS
Die => result ← $Failure;
};
ToNames: PUBLIC PROCEDURE [in: IO.STREAM, out: IO.STREAM, nameList: LIST OF Rope.ROPE]
RETURNS [result: REFNIL, msg: Rope.ROPENIL] = {
FSErrorMsg: PROC [error: FS.ErrorDesc] RETURNS [Rope.ROPE] = {
SELECT error.group FROM
lock => RETURN[" -- locked!\n"];
ENDCASE =>
IF error.code = $unknownFile
THEN RETURN [" -- not found!\n"]
ELSE RETURN[Rope.Cat[" -- FS.Error: ", error.explanation, "\n"]];
};
nBytesRead: NAT ← 0;
block: REF TEXTNEW[TEXT[256]];
streamList: LIST OF IO.STREAMNIL;
fileStream: IO.STREAM;
FOR left: LIST OF Rope.ROPE ← nameList, left.rest WHILE left # NIL DO
fileStream ←
FS.StreamOpen[fileName: FileNames.ResolveRelativePath[left.first],
accessOptions: $create !
FS.Error =>
IF error.group # $bug THEN {
msg ← Rope.Cat[left.first, FSErrorMsg[error]]; GO TO Die
}];
streamList ← CONS[fileStream, streamList];
ENDLOOP;
[result, msg] ← ToStreams[in: in, out: out, streamList: streamList];
FOR left: LIST OF IO.STREAM ← streamList, left.rest WHILE left # NIL DO
IF left.first # NIL THEN IO.Close[left.first];
ENDLOOP;
EXITS
Die => result ← $Failure;
};
ToStreams: PUBLIC PROCEDURE [in: IO.STREAM, out: IO.STREAM, streamList: LIST OF IO.STREAM]
RETURNS [result: REFNIL, msg: Rope.ROPENIL] = {
nBytesRead: NAT ← 0;
block: REF TEXTNEW[TEXT[256]];
WHILE NOT IO.EndOf[in] DO
block.length ← block.maxLength;
nBytesRead ← IO.GetBlock[in, block, 0, block.maxLength !
IO.EndOfStream => EXIT;
IO.Error => EXIT;
];
IO.PutBlock[out, block, 0, nBytesRead !
IO.EndOfStream => EXIT;
IO.Error => EXIT;
];
FOR left: LIST OF IO.STREAM ← streamList, left.rest WHILE left # NIL DO
IO.PutBlock[left.first, block, 0, nBytesRead !
IO.EndOfStream => EXIT;
IO.Error => EXIT;
];
ENDLOOP;
Process.CheckForAbort[];
ENDLOOP;
};
TeeCommand: Commander.CommandProc = {
[cmd: REF CommandObject] RETURNS [result: REFNIL, msg: ROPENIL]
CommandObject = [
in, out, err: IO.STREAM, commandLine, command: ROPE,
propertyList: List.AList, procData: CommandProcHandle]
arglist: LIST OF Rope.ROPE;
argc: NAT;
[arglist, argc] ← CommandTool.ParseToList[cmd, TRUE
! CommandTool.Failed => {msg ← errorMsg; GO TO Die}];
IF arglist = NIL
THEN {
msg ← "Usage: Tee filename ...";
}
ELSE {
[result, msg] ← ToNames[cmd^.in, cmd^.out, arglist];
};
EXITS
Die => result ← $Failure;
};
Commander.Register["Cat", CatCommand, "Cat [fileName | -] ... (to cmd^.out)"];
Commander.Register["Tee", TeeCommand, "Tee fileName ... (from cmd^.in)"];
}.