OpenRCommandsImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) July 1, 1985 9:20:03 pm PDT
DIRECTORY
BasicTime USING [GMT, nullGMT, Period],
BcdDefs USING [NullVersion, VersionStamp],
Commander USING [CommandProc, Handle, Register],
FS USING [Close, Error, FileInfo, GetName, Open, OpenFile],
IO USING [EndOfStream, GetTokenRope, IDProc, PutF, RIS, STREAM],
Process USING [CheckForAbort],
Rope USING [Cat, Compare, Concat, Equal, Fetch, Flatten, Index, Length, Match, ROPE, Run, Substr],
TiogaMenuOps USING [Open],
TiogaOps USING [FindDef],
UserProfile USING [Line],
VersionMap USING [Length, Map, MapList, Range, RangeList, RangeToEntry, ShortNameToRanges],
VersionMapDefaults USING [GetMapList],
ViewerClasses USING [Viewer];
OpenRCommandsImpl: CEDAR MONITOR
IMPORTS BasicTime, Commander, FS, IO, Process, Rope, TiogaMenuOps, TiogaOps, UserProfile, VersionMap, VersionMapDefaults
SHARES VersionMap
= BEGIN
Useful types
SourceFileList: TYPE = LIST OF SourceFileEntry;
SourceFileEntry: TYPE = RECORD[
map: VersionMap.Map, name: ROPE, created: BasicTime.GMT, 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 = {
[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];
eachFile: PROC = {
MyOpen: PROC [def: ROPENIL] = {
file: FS.OpenFile ← FS.Open[name: name, wantedCreatedTime: date
! FS.Error => {
IF error.code = $unknownFile
THEN {
IO.PutF[st, "Not found: %g\n", [rope[name]] ];
}
ELSE {
IO.PutF[st, "%g\n", [rope[error.explanation]] ];
};
result ← $Failure;
GO TO exit;
};
];
viewer: ViewerClasses.Viewer ← NIL;
name ← FS.GetName[file].fullFName;
FS.Close[file];
viewer ← TiogaMenuOps.Open[name];
IF viewer = NIL
THEN {
IO.PutF[st, "Not found: %g\n", [rope[r]] ];
result ← $Failure;
}
ELSE {
IO.PutF[st, "Opened: %g\n", [rope[r]] ];
result ← NIL;
IF Rope.Length[def] # 0 THEN
[] ← TiogaOps.FindDef[viewer, def, forwards, feedback];
};
EXITS exit => {};
};
sfl: SourceFileList ← NIL;
name: ROPENIL;
date: GMT;
r: ROPEIO.GetTokenRope[inStream, IO.IDProc].token;
IF Rope.Length[r] = 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, date] ← TryExtensions[sfl];
MyOpen[];
}
ELSE {
sfl ← FindSource[Rope.Concat[rBase, ".mesa"]];
[name, date] ← FindMostRecent[sfl];
MyOpen[rExt];
};
IF name = NIL THEN {
IO.PutF[st, "Sorry, '%g' is not in the current Cedar release.\n", [rope[r]]];
result ← $Failure;
RETURN;
};
};
ENDCASE => {
At least one match, so open the most recent
[name, date] ← FindMostRecent[sfl];
MyOpen[];
};
};
DO
eachFile[
! FS.Error => {msg ← error.explanation; result ← $Failed; EXIT};
IO.EndOfStream => EXIT;
];
ENDLOOP;
};
FindCommand: Commander.CommandProc = {
[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];
useBin: BOOL ← cmd.procData.clientData = $Bin;
eachFile: PROC = {
sfl: SourceFileList ← NIL;
r: ROPEIO.GetTokenRope[inStream, IO.IDProc].token;
IF Rope.Length[r] = 0 THEN RETURN;
IF NOT Rope.Match["*.*", r] THEN r ← Rope.Concat[r, ".*"];
sfl ← FindSource[r, FALSE, IF useBin THEN $Symbols ELSE $Source];
IF sfl = NIL THEN {
IO.PutF[st, "Sorry, '%g' is not in the current Cedar release.\n", [rope[r]] ];
RETURN;
};
IO.PutF[st, "%g =>\n", [rope[r]] ];
WHILE sfl # NIL DO
IO.PutF[st, " %g\n %g\n",
[rope[sfl.first.name]],
[time[sfl.first.created]]
];
sfl ← sfl.rest;
ENDLOOP;
};
DO
eachFile[
! FS.Error => {msg ← error.explanation; result ← $Failed; EXIT};
IO.EndOfStream => EXIT;
];
ENDLOOP;
};
FindSource: PROC [short: ROPE, removeDuplDates: BOOLTRUE, which: ATOMNIL] RETURNS [SourceFileList ← NIL] = TRUSTED {
size: INT ← Rope.Length[short];
starPos: INT ← short.Index[0, "*"];
match: BOOL ← starPos # size;
hasDot: BOOL ← short.Index[0, "."] # size;
rangeList: VersionMap.RangeList ← NIL;
head: SourceFileList ← NIL;
tail: SourceFileList ← NIL;
shortShort: ROPE ← Rope.Flatten[short, 0, starPos];
shortShortLen: INT ← Rope.Length[shortShort];
mapList: MapList ← NIL;
IF size = 0 THEN RETURN;
IF which = NIL THEN which ← $Source;
IF mapList = NIL THEN mapList ← VersionMapDefaults.GetMapList[which];
rangeList ← VersionMap.ShortNameToRanges[mapList, short];
WHILE rangeList # NIL DO
range: VersionMap.Range ← rangeList.first;
map: Map = range.map;
rangeList ← rangeList.rest;
Process.CheckForAbort[];
IF match
THEN {
entries: CARDINAL = VersionMap.Length[map];
IF range.first >= entries THEN LOOP;
range.len ← entries - range.first;
WHILE range.len # 0 DO
fullName: ROPE;
stamp: VersionStamp;
thisShort: ROPE;
created: BasicTime.GMT;
[fullName, stamp, created, 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, created: created, 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;
created: BasicTime.GMT;
[fullName, stamp, created, range] ← VersionMap.RangeToEntry[range];
new ← LIST[[map: range.map, name: fullName, created: created, stamp: stamp]];
IF tail = NIL THEN head ← new ELSE tail.rest ← new;
tail ← new;
ENDLOOP;
};
ENDLOOP;
RemoveDuplicates[head, removeDuplDates];
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 ← Rope.Length[r];
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, date: GMT] = {
IF sfl # NIL THEN {
date ← sfl.first.created;
name ← sfl.first.name;
FOR each: SourceFileList ← sfl.rest, each.rest WHILE each # NIL DO
eachDate: GMT ← each.first.created;
period: INT ← BasicTime.Period[from: date, to: eachDate];
IF period >= 0 THEN {
the file in each is more recent or the same date
eachName: ROPE ← each.first.name;
IF period < 0 OR Rope.Compare[eachName, name, FALSE] = greater THEN {
each is more recent OR (same date AND lexically greater name)
date ← eachDate;
name ← eachName;
};
};
ENDLOOP;
};
};
RemoveDuplicates: PROC [sfl: SourceFileList, removeDuplDates: BOOL] = {
This routine removes entries with duplicate names an (if removeDuplDates = TRUE) also removes entries with duplicate dates.
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;
SELECT TRUE FROM
Rope.Equal[each.first.name, entry.name, FALSE] => lag.rest ← next;
removeDuplDates AND each.first.stamp = thisStamp => lag.rest ← next;
ENDCASE => lag ← each;
each ← next;
ENDLOOP;
sfl ← sfl.rest;
ENDLOOP;
};
TryExtensions: PROC [sfl: SourceFileList] RETURNS [ROPENIL, GMT ← BasicTime.nullGMT] = {
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: each.first.created,
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;
};
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."];
Commander.Register [
"///Commands/FindR", FindCommand,
"Finds Cedar release source file names given the short names (.mesa extension is the default)"];
Commander.Register [
"///Commands/FindRBin", FindCommand,
"Finds Cedar release binary file names given the short names.",
$Bin];
};
Init[];
END.