OpenRCommandsImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Russ Atkinson, October 30, 1984 1:45:01 pm PST
DIRECTORY
BasicTime USING [FromPupTime, GMT, Period],
BcdDefs USING [NullVersion, VersionStamp],
Commander USING [CommandProc, Handle, Register],
FS USING [Error, FileInfo],
IO USING [EndOfStream, GetTokenRope, IDProc, PutF, RIS, STREAM],
Rope USING [Cat, Concat, Equal, Fetch, Flatten, Index, Length, Match, ROPE, Run, Size, Substr],
TiogaMenuOps USING [Open],
UserProfile USING [Line],
VersionMap USING [Length, Map, MapList, Range, RangeList, RangeToEntry, ShortNameToRanges],
VersionMapDefaults USING [GetMapList];
OpenRCommandsImpl: CEDAR MONITOR
IMPORTS BasicTime, Commander, FS, IO, Rope, TiogaMenuOps, UserProfile, VersionMap, VersionMapDefaults
SHARES VersionMap
= BEGIN
Useful types
SourceFileList: TYPE = LIST OF SourceFileEntry;
SourceFileEntry: TYPE = RECORD[map: VersionMap.Map, name: ROPE, stamp: VersionStamp];
GMT: TYPE = BasicTime.GMT;
Map: TYPE = VersionMap.Map;
MapList: TYPE = VersionMap.MapList;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
VersionStamp: TYPE = BcdDefs.VersionStamp;
NullVersion: VersionStamp = BcdDefs.NullVersion;
OpenCommand: Commander.CommandProc = TRUSTED {
[cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
Handle = REF [in, out, err: STREAM, commandLine,command: ROPE, propertyList: List.AList]
st: IO.STREAM ← cmd.out;
inStream: IO.STREAMIO.RIS[cmd.commandLine];
DO
sfl: SourceFileList ← NIL;
name: ROPENIL;
r: ROPEIO.GetTokenRope[inStream, IO.IDProc ! IO.EndOfStream => EXIT].token;
IF r.Size[] = 0 THEN RETURN;
sfl ← FindSource[r];
SELECT TRUE FROM
sfl = NIL => {
No file found as explicitly given, we might need to try some alternatives.
rBase, rExt: ROPE;
[rBase, rExt] ← SplitName[r];
IF rExt = NIL
THEN {
sfl ← FindSource[Rope.Concat[rBase, ".*"]];
name ← TryExtensions[sfl];
}
ELSE {
sfl ← FindSource[Rope.Concat[rBase, ".mesa"]];
name ← FindMostRecent[sfl];
name ← Rope.Cat[SplitName[name].prefix, ".", rExt];
};
IF name = NIL THEN {
IO.PutF[st, "Sorry, '%g' is not in the current Cedar release.\n", [rope[r]]];
result ← $Failure;
LOOP;
};
};
ENDCASE => {
At least one match, so open the most recent
name ← FindMostRecent[sfl];
};
IF TiogaMenuOps.Open[name] = NIL
THEN {
IO.PutF[st, "Not found: %g\n", [rope[r]] ];
result ← $Failure;
}
ELSE {
IO.PutF[st, "Opened: %g\n", [rope[r]] ];
result ← NIL;
};
ENDLOOP;
};
FindCommand: Commander.CommandProc = TRUSTED {
[cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
Handle = REF [in, out, err: STREAM, commandLine,command: ROPE, propertyList: List.AList]
st: IO.STREAM ← cmd.out;
inStream: IO.STREAMIO.RIS[cmd.commandLine];
DO
sfl: SourceFileList ← NIL;
r: ROPEIO.GetTokenRope[inStream, IO.IDProc ! IO.EndOfStream => EXIT].token;
IF r.Size[] = 0 THEN RETURN;
IF NOT Rope.Match["*.*", r] THEN r ← Rope.Concat[r, ".*"];
sfl ← FindSource[r, FALSE];
IF sfl = NIL THEN {
IO.PutF[st, "Sorry, '%g' is not in the current Cedar release.\n", [rope[r]] ];
LOOP;
};
IO.PutF[st, "%g =>\n", [rope[r]] ];
WHILE sfl # NIL DO
IO.PutF[st, " %g\n %g\n",
[rope[sfl.first.name]],
[time[BasicTime.FromPupTime[sfl.first.stamp.time]]]
];
sfl ← sfl.rest;
ENDLOOP;
ENDLOOP;
};
FindSource: PROC
[short: ROPE, removeDupl: BOOLTRUE] RETURNS [SourceFileList ← NIL] = TRUSTED {
size: INT ← short.Size[];
match: BOOL ← short.Index[0, "*"] # size;
hasDot: BOOL ← short.Index[0, "."] # size;
rangeList: VersionMap.RangeList ← NIL;
head: SourceFileList ← NIL;
tail: SourceFileList ← NIL;
shortShort: ROPENIL;
mapList: MapList ← NIL;
IF size = 0 THEN RETURN;
IF match THEN {
shortShort ← Rope.Flatten[short, 0, short.Index[0, "*"]];
IF shortShort.Size[] = 0 THEN RETURN;
};
IF mapList = NIL THEN mapList ← VersionMapDefaults.GetMapList[$Source];
rangeList ← VersionMap.ShortNameToRanges[mapList, short];
WHILE rangeList # NIL DO
range: VersionMap.Range ← rangeList.first;
map: Map = range.map;
rangeList ← rangeList.rest;
IF match
THEN {
entries: CARDINAL = VersionMap.Length[map];
shortShortLen: INT = Rope.Size[shortShort];
IF range.first >= entries THEN LOOP;
range.len ← entries - range.first;
WHILE range.len # 0 DO
fullName: ROPE;
stamp: VersionStamp;
thisShort: ROPE;
[fullName, stamp, range] ← VersionMap.RangeToEntry[range];
thisShort ← ShortName[fullName];
IF Rope.Run[shortShort, 0, thisShort, 0, FALSE] # shortShortLen THEN EXIT;
IF Rope.Match[short, thisShort, FALSE] THEN {
new: SourceFileList ← LIST[[map: range.map, name: fullName, stamp: stamp]];
IF tail = NIL THEN head ← new ELSE tail.rest ← new;
tail ← new;
};
ENDLOOP;
}
ELSE {
WHILE range.len # 0 DO
new: SourceFileList;
fullName: ROPE;
stamp: VersionStamp;
[fullName, stamp, range] ← VersionMap.RangeToEntry[range];
new ← LIST[[map: range.map, name: fullName, stamp: stamp]];
IF tail = NIL THEN head ← new ELSE tail.rest ← new;
tail ← new;
ENDLOOP;
};
ENDLOOP;
IF removeDupl THEN RemoveDuplicates[head];
RETURN [head];
};
ShortName: PROC [r: ROPE] RETURNS [ROPE] = {
make a long name into a short one
assumes a valid long name, of course
first: INT ← 0;
last: INT ← r.Size[];
FOR i: INT DECREASING IN [0..last) DO
c: CHAR ← r.Fetch[i];
SELECT c FROM
'>, '/ => {first ← i+1; EXIT};
'! => last ← i
ENDCASE;
ENDLOOP;
RETURN [r.Substr[first, last - first]]
};
SplitName: PROC [name: ROPE] RETURNS [prefix: ROPENIL, ext: ROPENIL] = {
dot: INT ← 0;
len: INT ← Rope.Length[name];
pos: INT ← len;
WHILE (pos ← pos - 1) > 0 DO
SELECT Rope.Fetch[name, pos] FROM
'! => {name ← Rope.Flatten[name, 0, pos]; len ← pos};
'. => {prefix ← Rope.Flatten[name, 0, pos]; ext ← Rope.Flatten[name, pos+1]; RETURN};
'], '/, '> => EXIT;
ENDCASE;
ENDLOOP;
RETURN [name, NIL];
};
FindMostRecent: PROC [sfl: SourceFileList] RETURNS [name: ROPENIL] = {
IF sfl # NIL THEN {
date: GMT ← TimeFromVersion[sfl.first.stamp];
name ← sfl.first.name;
FOR each: SourceFileList ← sfl.rest, each.rest WHILE each # NIL DO
eachDate: GMT ← TimeFromVersion[each.first.stamp];
IF BasicTime.Period[eachDate, date] > 0 THEN {
date ← eachDate;
name ← each.first.name;
};
ENDLOOP;
};
};
RemoveDuplicates: PROC [sfl: SourceFileList] = {
WHILE sfl # NIL DO
entry: SourceFileEntry ← sfl.first;
thisStamp: VersionStamp ← entry.stamp;
each: SourceFileList ← sfl.rest;
lag: SourceFileList ← sfl;
WHILE each # NIL DO
next: SourceFileList ← each.rest;
IF each.first.stamp = thisStamp
THEN lag.rest ← next
ELSE lag ← each;
each ← next;
ENDLOOP;
sfl ← sfl.rest;
ENDLOOP;
};
TryExtensions: PROC [sfl: SourceFileList] RETURNS [ROPENIL] = {
line: ROPE ← UserProfile.Line["SourceFileExtensions", "mesa tioga df cm config"];
in: STREAMIO.RIS[line, NIL];
DO
token: ROPEIO.GetTokenRope[in, IO.IDProc ! IO.EndOfStream => EXIT].token;
currentList: SourceFileList ← NIL;
IF Rope.Length[token] = 0 THEN EXIT;
FOR each: SourceFileList ← sfl, each.rest WHILE each # NIL DO
name: ROPE ← each.first.name;
base, ext: ROPENIL;
[base, ext] ← SplitName[name];
IF Rope.Equal[ext, token, FALSE] THEN {
name ← FS.FileInfo[
name: Rope.Cat[base, ".", token],
wantedCreatedTime: TimeFromVersion[each.first.stamp],
remoteCheck: FALSE
! FS.Error =>
SELECT error.code FROM
$unknownFile, $unknownCreatedTime => LOOP;
ENDCASE
].fullFName;
currentList ← CONS[each.first, currentList];
};
ENDLOOP;
IF currentList # NIL THEN RETURN [FindMostRecent[currentList]];
ENDLOOP;
};
TimeFromVersion: PROC [version: VersionStamp] RETURNS [GMT] = {
RETURN [BasicTime.FromPupTime[version.time]];
};
Init: PROC = TRUSTED {
Commander.Register [
"///Commands/OpenR", OpenCommand,
"Opens viewers on Cedar release source files given the short names (.mesa extension is the default). If a short name has multiple long names associated with it, the alternatives are listed, and no viewer is opened for that name. No spelling correction is performed."];
Commander.Register [
"///Commands/FindR", FindCommand,
"Finds Cedar release source file names given the short names (.mesa extension is the default). No spelling correction is performed."];
};
Init[];
END.