TiogaUnixFilter.mesa
Copyright Ó 1993 by Xerox Corporation. All rights reserved.
Last tweaked by Mike Spreitzer February 1, 1993 1:15 pm PST
DIRECTORY Feedback, FeedbackClasses, IO, MessageWindow, Rope, TEditDocument, TEditInput, TEditInputExtras, TEditInputOps, TEditSelection, TextEdit, TextLooks, TextNode, ThisMachine, Tioga, TiogaRopes, UnixErrno, UnixSysCallExtensions, UnixSysCalls, UXIO, UXStrings, ViewerClasses;
TiogaUnixFilter: CEDAR MONITOR
IMPORTS Feedback, FeedbackClasses, IO, MessageWindow, Rope, TEditInput, TEditInputExtras, TEditInputOps, TEditSelection, TextEdit, TextNode, ThisMachine, TiogaRopes, UnixErrno, UnixSysCallExtensions, UnixSysCalls, UXIO, UXStrings
={
ROPE: TYPE ~ Rope.ROPE;
router: Feedback.MsgRouter ¬ Feedback.EnsureRouter[$TiogaUnixFilter];
routerStream: IO.STREAM ¬ FeedbackClasses.CreateStreamOnRouter[router, $stderr];
GrainFudge: ARRAY TEditDocument.SelectionGrain OF INT ~ [
point: 0,
char: 1,
word: 1,
node: 0,
branch: 0];
UnixFilter: PROC [data: REF ANY, viewer: ViewerClasses.Viewer ¬ NIL, param: REF ¬ NIL] RETURNS [recordAtom: BOOL ¬ TRUE, quit: BOOL ¬ FALSE] --TEditInputExtras.CommandClosureProc-- ~ {
filterCmd: ROPE ¬ NIL;
Doit: PROC [root: Tioga.Node, tSel: TEditInputOps.Selection] ~ {
start: Tioga.Location ~ [tSel.start.pos.node, IF tSel.start.pos.where=Tioga.NodeItself THEN 0 ELSE MIN[tSel.start.pos.where, TextNode.EndPos[tSel.start.pos.node]]];
end: Tioga.Location ~ [tSel.end.pos.node, IF tSel.end.pos.where=Tioga.NodeItself THEN TextNode.EndPos[tSel.end.pos.node] ELSE MIN[tSel.end.pos.where, TextNode.EndPos[tSel.end.pos.node]]];
len: INT ~ TextNode.LocOffset[start, end, 1, TRUE] + GrainFudge[tSel.granularity];
orgR: ROPE ~ TiogaRopes.RopeFromTioga[node: start.node, start: start.where, length: len, skipCommentNode: FALSE];
orgFN: ROPE ~ NewName["old"];
newFN: ROPE ~ NewName["new"];
errFN: ROPE ~ NewName["err"];
fullCmd: ROPE ~ filterCmd;
SetContents[orgFN, orgR !
UXIO.Error => {
Feedback.PutFL[router, oneLiner, $Error, "UXIO.Error[%g, %g] writing old contents", LIST[ [atom[error.code]], [rope[error.explanation]] ]];
GOTO GiveUp};
IO.Error => {
Feedback.PutFL[router, oneLiner, $Error, "IO.Error[%g, %g (%g)] writing old contents", LIST[ [atom[IO.AtomFromErrorCode[ec]]], [rope[msg]], [refAny[details]] ]];
GOTO GiveUp};
];
{ENABLE UNWIND => Delete[orgFN];
Delete[newFN];
{res: INT ~ UnixSysCallExtensions.Spawn[
cmd: UXStrings.Create[fullCmd],
stdin: UXStrings.Create[orgFN],
stdout: UXStrings.Create[newFN],
stderr: UXStrings.Create[errFN] ];
errno: UnixErrno.Errno ~ UnixErrno.GetErrno[];
{ENABLE UNWIND => {Delete[newFN]; Delete[errFN]};
errR: ROPE;
IF res#0 THEN {
Feedback.PutFL[router, oneLiner, $Error, "UnixFilter op (%g) failed, res=%g, errno=%g.", LIST[ [rope[fullCmd]], [integer[res]], [integer[errno.ORD]] ]];
}
ELSE {
errR: ROPE ~ GetContents[errFN];
newR: ROPE ~ GetContents[newFN];
p1, p2: Tioga.Location;
looks: TextLooks.Looks;
IF newR=NIL THEN {
Feedback.Append[router, oneLiner, $Error, "no results written"];
GOTO GiveUp};
TEditInputOps.Delete[saveForPaste: FALSE];
p1 ¬ p2 ¬ TEditSelection.InsertionPoint[TEditSelection.pSel];
looks ¬ tSel.looks;
TEditSelection.Deselect[primary];
p2.where ¬ p1.where + TextEdit.ReplaceByRope[root: root,
dest: p1.node, start: p1.where, len: 0,
rope: newR, looks: looks, charSet: 0, charProps: NIL,
event: TEditInput.currentEvent].resultLen;
IF p2.where#p1.where THEN {
tSel.start.pos ¬ p1;
tSel.end.pos ¬ [p2.node, p2.where-1];
tSel.granularity ¬ char;
tSel.pendingDelete ¬ FALSE;
TEditSelection.MakeSelection[tSel, primary];
Feedback.Append[router, oneLiner, $FYI, "Done"];
}
ELSE Feedback.Append[router, oneLiner, $FYI, "Empty result"];
IF errR.Length[]>0 THEN routerStream.PutF1["error: \"%q\"", [rope[errR]] ];
};
}}}--enables--;
Delete[orgFN];
Delete[newFN];
Delete[errFN];
RETURN;
EXITS GiveUp => quit ¬ TRUE;
};
IF param#NIL THEN WITH param SELECT FROM
x: ROPE => filterCmd ¬ x;
ENDCASE => NULL;
IF filterCmd=NIL THEN {
MessageWindow.Append["Bogus PARAM", TRUE];
MessageWindow.Blink[];
RETURN [quit: TRUE]};
TEditInputOps.CallWithLocks[Doit];
RETURN [quit: TRUE]};
UnixFileFilter: PROC [data: REF ANY, viewer: ViewerClasses.Viewer ¬ NIL, param: REF ¬ NIL] RETURNS [recordAtom: BOOL ¬ TRUE, quit: BOOL ¬ FALSE] --TEditInputExtras.CommandClosureProc-- ~ {
filterCmd: ROPE ¬ NIL;
Doit: PROC [root: Tioga.Node, tSel: TEditInputOps.Selection] ~ {
start: Tioga.Location ~ [tSel.start.pos.node, IF tSel.start.pos.where=Tioga.NodeItself THEN 0 ELSE MIN[tSel.start.pos.where, TextNode.EndPos[tSel.start.pos.node]]];
end: Tioga.Location ~ [tSel.end.pos.node, IF tSel.end.pos.where=Tioga.NodeItself THEN TextNode.EndPos[tSel.end.pos.node] ELSE MIN[tSel.end.pos.where, TextNode.EndPos[tSel.end.pos.node]]];
len: INT ~ TextNode.LocOffset[start, end, 1, TRUE] + GrainFudge[tSel.granularity];
orgR: ROPE ~ TiogaRopes.RopeFromTioga[node: start.node, start: start.where, length: len, skipCommentNode: FALSE];
orgFN: ROPE ~ NewName["old"];
newFN: ROPE ~ NewName["new"];
outFN: ROPE ~ NewName["out"];
errFN: ROPE ~ NewName["err"];
fullCmd: ROPE ~ Replace[filterCmd, orgFN, newFN];
SetContents[orgFN, orgR !
UXIO.Error => {
Feedback.PutFL[router, oneLiner, $Error, "UXIO.Error[%g, %g] writing old contents", LIST[ [atom[error.code]], [rope[error.explanation]] ]];
GOTO GiveUp};
IO.Error => {
Feedback.PutFL[router, oneLiner, $Error, "IO.Error[%g, %g (%g)] writing old contents", LIST[ [atom[IO.AtomFromErrorCode[ec]]], [rope[msg]], [refAny[details]] ]];
GOTO GiveUp};
];
{ENABLE UNWIND => Delete[orgFN];
Delete[newFN];
{res: INT ~ UnixSysCallExtensions.Spawn[
cmd: UXStrings.Create[fullCmd],
stdin: UXStrings.Create["/dev/null"],
stdout: UXStrings.Create[outFN],
stderr: UXStrings.Create[errFN] ];
errno: UnixErrno.Errno ~ UnixErrno.GetErrno[];
{ENABLE UNWIND => {Delete[outFN]; Delete[errFN]};
errR: ROPE;
IF res#0 THEN {
Feedback.PutFL[router, oneLiner, $Error, "UnixFilter op (%g) failed, res=%g, errno=%g.", LIST[ [rope[fullCmd]], [integer[res]], [integer[errno.ORD]] ]];
}
ELSE {
errR: ROPE ~ GetContents[errFN];
outR: ROPE ~ GetContents[outFN];
newR: ROPE ~ GetContents[newFN];
p1, p2: Tioga.Location;
looks: TextLooks.Looks;
IF newR=NIL THEN {
Feedback.Append[router, oneLiner, $Error, "no results written"];
GOTO GiveUp};
TEditInputOps.Delete[saveForPaste: FALSE];
p1 ¬ p2 ¬ TEditSelection.InsertionPoint[TEditSelection.pSel];
looks ¬ tSel.looks;
TEditSelection.Deselect[primary];
p2.where ¬ p1.where + TextEdit.ReplaceByRope[root: root,
dest: p1.node, start: p1.where, len: 0,
rope: newR, looks: looks, charSet: 0, charProps: NIL,
event: TEditInput.currentEvent].resultLen;
IF p2.where#p1.where THEN {
tSel.start.pos ¬ p1;
tSel.end.pos ¬ [p2.node, p2.where-1];
tSel.granularity ¬ char;
tSel.pendingDelete ¬ FALSE;
TEditSelection.MakeSelection[tSel, primary];
Feedback.Append[router, oneLiner, $FYI, "Done"];
}
ELSE Feedback.Append[router, oneLiner, $FYI, "Empty result"];
IF outR.Length[]>0 THEN routerStream.PutF1["output: \"%q\"", [rope[outR]] ];
IF errR.Length[]>0 THEN routerStream.PutF1["error: \"%q\"", [rope[errR]] ];
};
}}}--enables--;
Delete[orgFN];
Delete[newFN];
Delete[outFN];
Delete[errFN];
RETURN;
EXITS GiveUp => quit ¬ TRUE;
};
IF param#NIL THEN WITH param SELECT FROM
x: ROPE => filterCmd ¬ x;
ENDCASE => NULL;
IF filterCmd=NIL THEN {
MessageWindow.Append["Bogus PARAM", TRUE];
MessageWindow.Blink[];
RETURN [quit: TRUE]};
TEditInputOps.CallWithLocks[Doit];
RETURN [quit: TRUE]};
processorID: ROPE ~ ThisMachine.ProcessorID[$Hex];
uid: INT ¬ 0;
NewName: ENTRY PROC [var: ROPE] RETURNS [ROPE] ~ {
ENABLE UNWIND => NULL;
processID: INT ~ UnixSysCalls.GetPID[];
uid ¬ uid+1;
RETURN IO.PutFLR[".unix-filter-temp-%g-%g-%g-%g", LIST[ [rope[var]], [rope[processorID]], [integer[processID]], [integer[uid]] ]]};
SetContents: PROC [fn, r: ROPE] ~ {
s: IO.STREAM ~ UXIO.CreateFileStream[fn, write];
s.PutRope[r];
s.Close[];
RETURN};
GetContents: PROC [fn: ROPE] RETURNS [r: ROPE] ~ {
s: IO.STREAM ¬ NIL;
s ¬ UXIO.CreateFileStream[fn, read !UXIO.Error, IO.Error => CONTINUE];
IF s=NIL THEN RETURN [NIL];
r ¬ IO.GetRope[s];
IO.Close[s];
RETURN};
Delete: PROCEDURE [fn: ROPE] ~ {
UXIO.Delete[fn !UXIO.Error => CONTINUE];
RETURN};
Replace: PROC [r, fn1, fn2: ROPE] RETURNS [ROPE] ~ {
i: INT ¬ 0;
l: INT ¬ r.Length[];
WHILE i<l DO
c: CHAR ¬ r.Fetch[i];
IF c#'$ OR i+1=l THEN i ¬ i+1
ELSE SELECT (c ¬ r.Fetch[i+1]) FROM
'1, '2 => {repl: ROPE ~ IF c='1 THEN fn1 ELSE fn2;
r ¬ Rope.Replace[r, i, 2, repl];
i ¬ i+repl.Length[];
l ¬ r.Length[]};
'$ => l ¬ (r ¬ Rope.Replace[r, i, 1, NIL]).Length[];
ENDCASE => i ¬ i+1;
ENDLOOP;
RETURN [r]};
TEditInputExtras.RegisterClosure[[$UnixFilter, UnixFilter, NIL]];
TEditInputExtras.RegisterClosure[[$UnixFileFilter, UnixFileFilter, NIL]];
}.