<> <> <> 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 <> 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: REF _ NIL, msg: ROPE _ NIL]>> <> st: IO.STREAM _ cmd.out; inStream: IO.STREAM _ IO.RIS[cmd.commandLine]; eachFile: PROC = { MyOpen: PROC [def: ROPE _ NIL] = { 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: ROPE _ NIL; date: GMT; r: ROPE _ IO.GetTokenRope[inStream, IO.IDProc].token; IF Rope.Length[r] = 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, 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 => { <> [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: REF _ NIL, msg: ROPE _ NIL]>> <> st: IO.STREAM _ cmd.out; inStream: IO.STREAM _ IO.RIS[cmd.commandLine]; useBin: BOOL _ cmd.procData.clientData = $Bin; eachFile: PROC = { sfl: SourceFileList _ NIL; r: ROPE _ IO.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: BOOL _ TRUE, which: ATOM _ NIL] 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] = { <> <> 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: 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, 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 { <> 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, removeDuplDates: BOOL] = { <> 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 [ROPE _ NIL, GMT _ BasicTime.nullGMT] = { 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: 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.