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, Compare, 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 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 { st: IO.STREAM _ cmd.out; inStream: IO.STREAM _ IO.RIS[cmd.commandLine]; DO sfl: SourceFileList _ NIL; name: ROPE _ NIL; r: ROPE _ IO.GetTokenRope[inStream, IO.IDProc ! IO.EndOfStream => EXIT].token; IF r.Size[] = 0 THEN RETURN; sfl _ FindSource[r]; SELECT TRUE FROM sfl = NIL => { 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 => { 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 { st: IO.STREAM _ cmd.out; inStream: IO.STREAM _ IO.RIS[cmd.commandLine]; DO sfl: SourceFileList _ NIL; r: ROPE _ IO.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: BOOL _ TRUE] 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: ROPE _ NIL; 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] = { 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: ROPE _ NIL, ext: ROPE _ NIL] = { 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: ROPE _ NIL] = { 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]; period: INT _ BasicTime.Period[from: date, to: eachDate]; IF period >= 0 THEN { eachName: ROPE _ each.first.name; IF period < 0 OR Rope.Compare[eachName, name, FALSE] = greater THEN { date _ eachDate; name _ eachName; }; }; 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 [ROPE _ NIL] = { line: ROPE _ UserProfile.Line["SourceFileExtensions", "mesa tioga df cm config"]; in: STREAM _ IO.RIS[line, NIL]; DO token: ROPE _ IO.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: ROPE _ NIL; [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. μOpenRCommandsImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Russ Atkinson, November 8, 1984 12:33:13 pm PST Useful types [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Handle = REF [in, out, err: STREAM, commandLine,command: ROPE, propertyList: List.AList] No file found as explicitly given, we might need to try some alternatives. At least one match, so open the most recent [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Handle = REF [in, out, err: STREAM, commandLine,command: ROPE, propertyList: List.AList] make a long name into a short one assumes a valid long name, of course the file in each is more recent or the same date each is more recent OR (same date AND lexically greater name) Κ O˜šœ™Jšœ Οmœ1™