DIRECTORY AMBridge USING [ContextPC], AMModel USING [Context, ContextSection, RootContext, Section, SectionSource, SectionVersion, Source, SourceFileName, SourceObj, SourceSection, SourceVersion], AMModelBridge USING [LoadedSection, LoadedSectionForProc, LoadedSectionForProgPC], AMViewerOps USING [ReportProc, SelectionOption, Severity], AMTypes USING [GlobalParent, TVType, UnderClass], BBContext, BBSafety USING [Mother], BcdDefs USING [NullVersion, VersionStamp], Commander USING [CommandProc, Handle, Register], Convert USING [ValueToRope], Directory USING [Error, GetProps, Lookup], File USING [Capability], FileLookup USING [LookupFile, Result], LSD USING [Entry, Lookup], IO, List, Process USING [Pause, SecondsToTicks], ProcessProps, PutGet USING [FromRope], Rope, RTBasic USING [TV], System USING [GreenwichMeanTime], TEditDocument USING [LineTable, TEditDocumentData], TEditImpl USING [InitTEditDocument], TEditScrolling USING [AutoScroll, ScrollToPosition], TEditTouchup USING [LockAfterRefresh, UnlockAfterRefresh], TextNode USING [Forward, Location, Ref], TimeStamp USING [Null, Stamp], TiogaMenuOps USING [DefaultMenus, Open], TiogaOps USING [GetSelection, Location, LocOffset, LocRelative, Ref, Root, SetSelection, ViewerDoc], VersionMap USING [FetchName, FetchStamp, Length, Map, MapList], VersionMapDefaults USING [FileNameFromVersion, GetMapList], VersionMapOps USING [SourceFileEntry, SourceFileList], ViewerClasses USING [Viewer], ViewerOps USING [EnumerateViewers, EnumProc, OpenIcon], ViewerTools USING [MakeNewTextViewer, SelPos, SelPosRec, SetSelection], WorldVM USING [LocalWorld, World]; AMViewerOpsImpl: CEDAR MONITOR IMPORTS AMBridge, AMModel, AMModelBridge, AMTypes, BBContext, BBSafety, Commander, Convert, Directory, FileLookup, List, LSD, IO, Process, ProcessProps, PutGet, Rope, TEditImpl, TEditScrolling, TEditTouchup, TextNode, TiogaMenuOps, TiogaOps, VersionMap, VersionMapDefaults, ViewerOps, ViewerTools, WorldVM EXPORTS AMViewerOps, VersionMapOps SHARES VersionMap = BEGIN OPEN AMViewerOps, RTBasic; Section: TYPE = AMModel.Section; Source: TYPE = AMModel.Source; SourceFileEntry: TYPE = VersionMapOps.SourceFileEntry; SourceFileList: TYPE = VersionMapOps.SourceFileList; LoadedSection: TYPE = AMModelBridge.LoadedSection; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; TV: TYPE = RTBasic.TV; World: TYPE = WorldVM.World; ropeCreator: PROC [name: ROPE] RETURNS [rope: ROPE] _ NIL; oldSetSel: BOOL _ FALSE; AutoScrollOK: BOOL _ TRUE; skipComments: BOOL _ TRUE; lagLagMsg, lagMsg: ROPE _ NIL; lagErr: ROPE _ NIL; SourceError: PUBLIC ERROR [reason: ROPE] = CODE; ReportError: PUBLIC ERROR [msg: ROPE, severity: Severity] = CODE; SourceFromTV: PUBLIC PROC [tv: TV, report: ReportProc] RETURNS [name: ROPE _ NIL, index: INT _ -1] = { errmsg: ROPE _ NIL; inner: PROC = TRUSTED { section: Section _ NIL; source: Source _ NIL; SELECT AMTypes.UnderClass[AMTypes.TVType[tv]] FROM procedure => section _ AMModelBridge.LoadedSectionForProc[tv].section; globalFrame => section _ AMModel.ContextSection[tv]; localFrame => { section _ AMModelBridge.LoadedSectionForProgPC[ prog: AMTypes.GlobalParent[tv], pc: AMBridge.ContextPC[tv]].section; }; ENDCASE => {errmsg _ "invalid TV"; RETURN}; source _ AMModel.SectionSource[section]; name _ SourceToFullName[source, report]; IF name = NIL THEN { errmsg _ VersionExpectedMessage[AMModel.SourceVersion[source]]; RETURN}; WITH s: source^ SELECT FROM entire => index _ 0; field => index _ s.firstCharIndex; ENDCASE => ERROR; }; err: ROPE _ NIL; Report[report, comment, " Finding source... "]; err _ BBSafety.Mother[inner]; IF errmsg = NIL THEN errmsg _ err; IF errmsg # NIL THEN Report[report, fatal, " No source: ", errmsg] ELSE Report[report, success, NIL]; }; OpenSource: PUBLIC PROC [name: ROPE, index: INT, chars: INT _ 2, report: ReportProc] = { viewer: ViewerClasses.Viewer _ NIL; inner: PROC = TRUSTED { viewer _ NameToOpenViewer[name, report]; IF viewer # NIL AND index > 0 THEN SetSel[viewer, index, chars, name]; }; err: ROPE _ NIL; err _ BBSafety.Mother[inner]; IF err # NIL THEN Report[report, fatal, " Can't open: ", err] ELSE Report[report, success, " Source opened."]; }; ViewerFromSection: PUBLIC PROC [section: AMModel.Section, report: ReportProc] RETURNS [viewer: ViewerClasses.Viewer _ NIL] = TRUSTED { errmsg: ROPE _ NIL; inner: PROC = TRUSTED { sourceVersion: BcdDefs.VersionStamp; source: Source _ AMModel.SectionSource[section]; name: ROPE _ AMModel.SourceFileName[source]; start: INT _ 0; IF name = NIL THEN { errmsg _ "can't get source name"; RETURN}; sourceVersion _ AMModel.SourceVersion[source]; IF sourceVersion = BcdDefs.NullVersion THEN { errmsg _ "can't get source version stamp"; RETURN}; name _ SourceToFullName[source, report]; IF name = NIL THEN { errmsg _ VersionExpectedMessage[sourceVersion]; RETURN}; errmsg _ "can't set source"; viewer _ NameToOpenViewer[name, report]; errmsg _ "can't set selection"; WITH s: source^ SELECT FROM field => start _ s.firstCharIndex; ENDCASE; SetSel[viewer, start, 2, name]; errmsg _ NIL; }; msg: ROPE _ BBSafety.Mother[inner]; IF errmsg = NIL THEN errmsg _ msg; IF errmsg # NIL THEN Report[report, fatal, errmsg]; }; SourceFromSelection: PUBLIC PROC [which: SelectionOption _ primary] RETURNS [name: ROPE _ NIL, index: INT _ -1] = TRUSTED { viewer: ViewerClasses.Viewer _ NIL; start: TiogaOps.Location; [viewer: viewer, start: start] _ TiogaOps.GetSelection[IF which = primary THEN primary ELSE feedback]; IF viewer # NIL AND NOT viewer.destroyed AND NOT viewer.newFile THEN { root: TiogaOps.Ref _ TiogaOps.Root[start.node]; offset: INT _ TiogaOps.LocOffset[loc1: [root, 0], loc2: start, skipCommentNodes: skipComments]; index _ offset; name _ viewer.name; }; }; SectionFromSelection: PUBLIC PROC [world: World _ NIL, which: SelectionOption _ primary] RETURNS [section: Section _ NIL, contexts: LIST OF AMModel.Context _ NIL] = TRUSTED { name: ROPE _ NIL; index: INT _ -1; [name, index] _ SourceFromSelection[which]; [section, contexts] _ SectionFromSource[world, name, index]; }; SectionFromSource: PUBLIC PROC [world: World _ NIL, name: ROPE _ NIL, index: INT _ 0] RETURNS [section: Section _ NIL, contexts: LIST OF AMModel.Context _ NIL] = TRUSTED { msg: ROPE _ NIL; inner: PROC = TRUSTED { sourceVersion: BcdDefs.VersionStamp _ FileVersion[name]; source: Source _ NIL; context: AMModel.Context _ AMModel.RootContext[IF world = NIL THEN WorldVM.LocalWorld[] ELSE world]; IF sourceVersion = BcdDefs.NullVersion THEN { msg _ "version not accessible"; RETURN; }; IF index <= 0 THEN source _ NEW[AMModel.SourceObj _ [ fileName: shortName, class: prog, versionStamp: sourceVersion, sourceRange: entire[]]] ELSE source _ NEW[AMModel.SourceObj _ [ fileName: shortName, class: statement, versionStamp: sourceVersion, sourceRange: field[index, index]]]; [section, contexts] _ AMModel.SourceSection[source, context]; }; shortName: ROPE _ StripDir[name]; err: ROPE _ NIL; IF Rope.Match["*.mesa", shortName, FALSE] THEN err _ BBSafety.Mother[inner] ELSE err _ Rope.Concat[shortName , " is not a mesa file!"]; IF msg # NIL THEN err _ msg; IF err # NIL THEN ERROR SourceError[lagErr _ err]; }; NameToOpenViewer: PROC [name: ROPE, report: ReportProc] RETURNS [viewer: ViewerClasses.Viewer _ NIL] = { remoteName: BOOL = Rope.SkipTo[name, 0, "/>"] # Rope.Size[name]; visit: ViewerOps.EnumProc = { IF Rope.Match["*.mesa*", v.name, FALSE] AND EqualNames[v.name, name] THEN { viewer _ v; RETURN [FALSE]}; }; ViewerOps.EnumerateViewers[visit]; IF viewer = NIL OR viewer.destroyed THEN TRUSTED { Report[report, comment, " Opening ", name, "... "]; IF remoteName AND ropeCreator # NIL THEN { rope: ROPE _ ropeCreator[name]; viewer _ ViewerTools.MakeNewTextViewer[ info: [name: name, column: left, iconic: TRUE], paint: FALSE]; viewer.data _ PutGet.FromRope[rope]; viewer.file _ name; TEditImpl.InitTEditDocument[viewer]; TiogaMenuOps.DefaultMenus[viewer]; } ELSE viewer _ TiogaMenuOps.Open[name]; }; IF viewer.iconic THEN ViewerOps.OpenIcon[viewer]; }; GFToVersionStamps: PUBLIC PROC [gf: TV] RETURNS [source,object: BcdDefs.VersionStamp _ BcdDefs.NullVersion] = TRUSTED { ENABLE {ABORTED => GO TO abort; ANY => GO TO oops}; section: AMModel.Section _ AMModel.ContextSection[gf]; src: AMModel.Source _ AMModel.SectionSource[section]; source _ AMModel.SourceVersion[src]; object _ AMModel.SectionVersion[section]; EXITS abort => ERROR ABORTED; oops => {}; }; FileVersion: PUBLIC PROC [name: ROPE] RETURNS [version: BcdDefs.VersionStamp _ BcdDefs.NullVersion] = TRUSTED { local: BOOL = Rope.SkipTo[name, 0, "/>"] = name.Size[]; IF local THEN { ENABLE Directory.Error => GO TO none; flat: ROPE _ name.Flatten[]; fc: File.Capability _ Directory.Lookup[LOOPHOLE[flat]]; garbage: STRING _ [64]; version.time _ LOOPHOLE[Directory.GetProps[fc, garbage].createDate]; } ELSE { entry: LSD.Entry _ LSD.Lookup[name]; IF entry = NIL THEN { host: ROPE _ "Indigo"; nameSansHost: ROPE _ name; pos: INT _ Rope.SkipTo[name, 0, "[/"]; result: FileLookup.Result; create: System.GreenwichMeanTime; IF pos = 0 AND pos # name.Size[] THEN { pos _ Rope.SkipTo[name, 1, "]/"]; host _ name.Flatten[1, pos-1]; nameSansHost _ name.Flatten[pos+1]; }; [result: result, create: create] _ FileLookup.LookupFile[host, nameSansHost]; IF result = ok THEN version.time _ LOOPHOLE[create]; } ELSE version.time _ LOOPHOLE[entry.create] }; EXITS none => {}; }; SourceToFullName: PUBLIC PROC [source: Source, report: ReportProc] RETURNS [name: ROPE] = TRUSTED { fileVersion,sourceVersion: BcdDefs.VersionStamp _ BcdDefs.NullVersion; name _ AMModel.SourceFileName[source]; IF NOT Rope.Match["*.mesa", name, FALSE] THEN name _ name.Concat[".mesa"]; fileVersion _ FileVersion[name]; sourceVersion _ AMModel.SourceVersion[source]; IF fileVersion = sourceVersion THEN RETURN [name]; Report[report, comment, " (version map) "]; name _ VersionMapDefaults.FileNameFromVersion[$Source, sourceVersion]; }; EqualNames: PROC [name1,name2: ROPE] RETURNS [BOOL] = { size1: INT _ name1.Size[]; size2: INT _ name2.Size[]; pos1,pos2: INT _ 0; WHILE pos1 < size1 AND pos2 < size2 DO c1: CHAR _ name1.Fetch[pos1]; c2: CHAR _ name2.Fetch[pos2]; pos1 _ pos1 + 1; pos2 _ pos2 + 1; IF c1 = c2 THEN LOOP; SELECT c1 FROM IN ['A..'Z] => c1 _ c1 + ('a-'A); '[, '>, '] => c1 _ '/; '< => { pos2 _ pos2 - 1; LOOP}; ENDCASE; SELECT c2 FROM IN ['A..'Z] => c2 _ c2 + ('a-'A); '[, '>, '] => c2 _ '/; '< => { pos1 _ pos1 - 1; LOOP}; ENDCASE; IF c1 # c2 THEN RETURN [FALSE]; ENDLOOP; RETURN [pos1 = size1 AND pos2 = size2]; }; StripDir: PROC [name: ROPE] RETURNS [Rope.Text] = { size,pos: INT _ name.Size[]; start: INT _ 0; WHILE (pos _ pos - 1) >= 0 DO SELECT name.Fetch[pos] FROM '! => EXIT; '. => {pos _ size; EXIT}; ENDCASE; ENDLOOP; start _ pos; WHILE start > 0 DO SELECT name.Fetch[start _ start - 1] FROM '/, '\\, '[, '], '<, '> => { start _ start + 1; EXIT}; ENDCASE; ENDLOOP; RETURN [name.Flatten[start, pos-start]]; }; VersionExpectedMessage: PROC [version: BcdDefs.VersionStamp] RETURNS [msg: ROPE] = TRUSTED { msg _ Rope.Cat [ "source of ", Convert.ValueToRope [[time[time: LOOPHOLE[version.time], useZone: TRUE]]], " expected"]; }; SetSel: PROC [viewer: ViewerClasses.Viewer, pos,len: INT, openName: ROPE _ NIL] = TRUSTED { WHILE viewer.iconic AND NOT viewer.destroyed DO ViewerOps.OpenIcon[viewer]; Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; IF viewer.destroyed THEN RETURN; IF oldSetSel THEN ViewerTools.SetSelection[viewer, NEW[ViewerTools.SelPosRec _ [pos, len]]] ELSE { x: TiogaOps.Ref _ TiogaOps.ViewerDoc[viewer]; loc1: TiogaOps.Location _ TiogaOps.LocRelative[location: [x, 0], count: pos, skipCommentNodes: skipComments]; loc2: TiogaOps.Location _ TiogaOps.LocRelative[location: loc1, count: len, skipCommentNodes: skipComments]; r: REF _ loc1.node; opaqueLoc: TextNode.Location _ [NARROW[r], loc1.where]; TiogaOps.SetSelection [ viewer: viewer, start: loc1, end: loc2, level: char, caretBefore: TRUE, pendingDelete: FALSE, which: feedback]; IF AutoScrollOK OR OnScreen[viewer, opaqueLoc] THEN TEditScrolling.AutoScroll[viewer: viewer, tryToGlitch: TRUE, id: feedback] ELSE TEditScrolling.ScrollToPosition[viewer, opaqueLoc]; }; }; OnScreen: PROC [viewer: ViewerClasses.Viewer, point: TextNode.Location] RETURNS [BOOL] = { IF viewer = NIL OR point.node = NIL THEN RETURN [FALSE]; IF viewer.destroyed OR viewer.iconic THEN RETURN [FALSE]; WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { IF TEditTouchup.LockAfterRefresh[tdd, "OnScreen"] THEN { ENABLE {UNWIND => TEditTouchup.UnlockAfterRefresh[tdd]}; lines: TEditDocument.LineTable _ tdd.lineTable; found: BOOL _ FALSE; IF lines # NIL AND lines.lastLine >= 4 THEN { first: TextNode.Location _ lines[1].pos; last: TextNode.Location _ lines[lines.lastLine-1].pos; each: TextNode.Ref _ first.node; IF point.node = first.node AND point.where < first.where THEN GO TO quickOut; IF point.node = last.node AND point.where > last.where THEN GO TO quickOut; WHILE each # NIL DO IF each = point.node THEN {found _ TRUE; EXIT}; IF each = last.node THEN EXIT; each _ TextNode.Forward[each].nx; ENDLOOP; EXITS quickOut => {}; }; TEditTouchup.UnlockAfterRefresh[tdd]; RETURN [found]; }; }; ENDCASE; RETURN [FALSE]; }; Report: PROC [report: ReportProc, severity: Severity, r1,r2,r3,r4: ROPE _ NIL] = { msg: ROPE _ Rope.Cat[r1,r2,r3,r4]; lagLagMsg _ lagMsg; lagMsg _ msg; IF report = NIL THEN { IF severity # fatal AND severity # warning THEN RETURN; ERROR ReportError[msg, severity]; }; report[msg, severity]; }; FindSource: PUBLIC PROC [short: ROPE, mapList: VersionMap.MapList _ NIL, firstOnly: BOOL _ FALSE] RETURNS [sfl: SourceFileList _ NIL] = TRUSTED { size: INT _ short.Size[]; match: INT _ -1; hasDot: BOOL _ short.Index[0, "."] # size; IF size = 0 THEN RETURN; IF short.Fetch[size-1] = '* THEN { match _ size _ size - 1; short _ short.Substr[0, match]; }; IF match <= 0 AND NOT hasDot THEN { short _ short.Concat[".mesa"]; size _ short.Size[]}; IF mapList = NIL THEN mapList _ VersionMapDefaults.GetMapList[$Source]; FOR list: VersionMap.MapList _ mapList, list.rest UNTIL list = NIL DO map: VersionMap.Map _ list.first; names: ROPE _ map.names; lag: INT _ names.Index[0, "\n"]; FOR i: INT IN [0..map.Length[]) DO anglePos: INT _ lag; versionPos: INT _ 0; dotPos: INT _ 0; next: INT _ names.Index[lag+1, "\n"]; FOR pos: INT DECREASING IN [lag..next) DO c: CHAR _ names.Fetch[pos]; SELECT c FROM '>, '/ => {anglePos _ pos; EXIT}; '. => IF dotPos = 0 THEN dotPos _ pos; '! => versionPos _ pos ENDCASE; ENDLOOP; IF anglePos < dotPos AND dotPos < versionPos THEN { start: INT _ anglePos + 1; target: INT _ IF match > 0 THEN match ELSE versionPos-start; IF target = size AND target = short.Run[0, names, start, FALSE] THEN { full: ROPE _ map.FetchName[i]; sfl _ CONS[[map: map, name: full, stamp: map.FetchStamp[i]], sfl]; IF firstOnly THEN RETURN; }; }; lag _ next; ENDLOOP; ENDLOOP; }; FindSourceInDir: PUBLIC PROC [dir, short: ROPE, mapList: VersionMap.MapList _ NIL, firstOnly: BOOL _ FALSE] RETURNS [sfl: SourceFileList _ NIL] = TRUSTED { size: INT _ short.Size[]; dirSize: INT = dir.Size[]; match: INT _ -1; hasDot: BOOL _ short.Index[0, "."] # size; IF size = 0 THEN RETURN; IF short.Fetch[size-1] = '* THEN { match _ size _ size - 1; short _ short.Substr[0, match]; }; IF match <= 0 AND NOT hasDot THEN { short _ short.Concat[".mesa"]; size _ short.Size[]}; IF mapList = NIL THEN mapList _ VersionMapDefaults.GetMapList[$Source]; FOR list: VersionMap.MapList _ mapList, list.rest UNTIL list = NIL DO map: VersionMap.Map _ list.first; names: ROPE _ map.names; lag: INT _ names.Index[0, "\n"]; FOR i: INT IN [0..map.Length[]) DO anglePos: INT _ lag; versionPos: INT _ 0; dotPos: INT _ 0; dirPos: INT _ -1; next: INT _ names.Index[lag+1, "\n"]; FOR pos: INT DECREASING IN [lag..next) DO c: CHAR _ names.Fetch[pos]; SELECT c FROM '>, '/ => {anglePos _ pos; EXIT}; '. => IF dotPos = 0 THEN dotPos _ pos; '! => versionPos _ pos ENDCASE; ENDLOOP; IF anglePos < dotPos AND dotPos < versionPos THEN { start: INT _ anglePos + 1; target: INT _ IF match > 0 THEN match ELSE versionPos-start; IF target = size AND target = short.Run[0, names, start, FALSE] THEN { full: ROPE _ map.FetchName[i]; -- get the full name new: SourceFileList _ NIL; IF dir # NIL THEN { dirPos: INT = Rope.Index[full, 0, dir, FALSE]; c: CHAR _ '/; IF dirPos = full.Size[] THEN GO TO notHere; IF dirPos > 0 THEN c _ full.Fetch[dirPos-1]; IF c # '/ AND c # '< THEN GO TO notHere; c _ full.Fetch[dirPos+dirSize]; IF c # '/ AND c # '> THEN GO TO notHere; }; sfl _ CONS[[map: map, name: full, stamp: map.FetchStamp[i]], sfl]; IF firstOnly THEN RETURN; EXITS notHere => {}; }; }; lag _ next; ENDLOOP; ENDLOOP; }; OpenViewerFromEntry: PROC [entry: SourceFileEntry] = TRUSTED { full: ROPE _ entry.name; short: ROPE _ ShortName[full]; stamp: TimeStamp.Stamp _ FileVersion[short]; readOnly: BOOL _ TRUE; IF stamp # TimeStamp.Null THEN { IF stamp = entry.stamp THEN { full _ short; readOnly _ FALSE}; }; OpenSource[full, 0, 0, ClarkKent]; }; 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]] }; OpenCommand: Commander.CommandProc = TRUSTED { st: IO.STREAM _ cmd.out; dir: ROPE _ NIL; each: PROC [r: ROPE] = TRUSTED { inStream: IO.STREAM _ IO.RIS[r]; DO sfl: SourceFileList _ NIL; r _ inStream.GetToken[! IO.EndOfStream => EXIT]; IF r.Size[] = 0 THEN RETURN; sfl _ RemoveDuplicates[FindSourceInDir[dir, r, NIL, FALSE]]; IF sfl = NIL THEN { st.PutRope["Sorry, '"]; st.PutRope[r]; st.PutRope["' is not in the current Cedar release.\n"]; RETURN}; IF sfl.rest # NIL THEN { st.PutRope["Sorry, multiple versions for '"]; st.PutRope[r]; st.PutRope["':"]; WHILE sfl # NIL DO st.PutRope["\n "]; st.PutRope[sfl.first.name]; st.PutRope[" "]; st.Put[[time[[sfl.first.stamp.time]]]]; sfl _ sfl.rest; ENDLOOP; st.PutRope["\n"]; RETURN}; OpenViewerFromEntry[sfl.first]; ENDLOOP; }; SELECT 5 FROM Rope.Run[cmd.command, 0, "openC", 0, FALSE] => dir _ "Cedar"; Rope.Run[cmd.command, 0, "openP", 0, FALSE] => dir _ "PreCedar"; ENDCASE; each[cmd.commandLine ! IO.UserAborted => {CONTINUE}]; }; OpenGlobalCommand: Commander.CommandProc = TRUSTED { st: IO.STREAM _ cmd.out; dir: ROPE _ NIL; each: PROC [r: ROPE] = TRUSTED { inStream: IO.STREAM _ IO.RIS[r]; gf: TV _ NIL; DO fileName: ROPE _ NIL; r _ inStream.GetToken[! IO.EndOfStream => EXIT]; IF r.Size[] = 0 THEN RETURN; gf _ BBContext.GlobalFrameSearch[context: NIL, frameName: r, case: FALSE].gf; IF gf = NIL THEN { st.PutRope[r]; st.PutRope[" can not be found.\n"]; LOOP; }; fileName _ SourceFromTV[gf, ClarkKent].name; IF fileName # NIL THEN OpenSource[fileName, 0, 0, ClarkKent]; ENDLOOP; }; each[cmd.commandLine ! IO.UserAborted => {CONTINUE}]; }; ClarkKent: AMViewerOps.ReportProc = TRUSTED { WITH List.Assoc[$CommanderHandle, ProcessProps.GetPropList[]] SELECT FROM cmd: Commander.Handle => { st: IO.STREAM _ cmd.out; st.PutRope[msg]; }; ENDCASE; }; RemoveDuplicates: PROC [sfl: SourceFileList] RETURNS [new: SourceFileList _ NIL] = { IF sfl # NIL THEN { entry: SourceFileEntry _ sfl.first; thisStamp: TimeStamp.Stamp _ entry.stamp; each: SourceFileList _ sfl.rest _ RemoveDuplicates[sfl.rest]; lag: SourceFileList _ new _ sfl; WHILE each # NIL DO next: SourceFileList _ each.rest; IF each.first.stamp = thisStamp THEN lag.rest _ next ELSE lag _ each; each _ next; ENDLOOP; }; }; FindCommand: Commander.CommandProc = TRUSTED { st: IO.STREAM _ cmd.out; each: PROC [r: ROPE] = TRUSTED { inStream: IO.STREAM _ IO.RIS[r]; DO sfl: SourceFileList _ NIL; r _ inStream.GetToken[! IO.EndOfStream => EXIT]; IF r.Size[] = 0 THEN RETURN; sfl _ RemoveDuplicates[FindSource[r, NIL, FALSE]]; IF sfl = NIL THEN { st.PutRope["Sorry, '"]; st.PutRope[r]; st.PutRope["' is not in the current Cedar release.\n"]; RETURN}; st.PutRope[r]; st.PutRope[" =>\n"]; sfl _ FindSource[r, NIL, FALSE]; IF sfl = NIL THEN { st.PutRope["Sorry, '"]; st.PutRope[r]; st.PutRope["' is not in the current Cedar release.\n"]; RETURN}; WHILE sfl # NIL DO st.PutRope[" "]; st.PutRope[sfl.first.name]; st.PutRope[" "]; st.Put[[time[[sfl.first.stamp.time]]]]; st.PutRope["\n"]; sfl _ sfl.rest; ENDLOOP; ENDLOOP; }; each[cmd.commandLine ! IO.UserAborted => {CONTINUE}]; }; Init: PROC = TRUSTED { Commander.Register [ "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 [ "openC", OpenCommand, "Like openr, but forces directory to be Cedar."]; Commander.Register [ "openG", OpenGlobalCommand, "Opens source for named global frame."]; Commander.Register [ "openP", OpenCommand, "Like openr, but forces directory to be PreCedar."]; Commander.Register [ "findr", FindCommand, "Finds Cedar release source file names given the short names (.mesa extension is the default). No spelling correction is performed."]; }; Init[]; END. DAMViewerOpsImpl.mesa Russ Atkinson, April 27, 1983 10:51 pm Useful types Global variables this is a crock to avoid using RopeFile.Create, yet allow us to test things EXPORTS to AMViewerOps gets the source file name and the source index for the given TV, which must be a local frame or global frame, if not successful, then name = NIL & index < 0 uses the results of GetSource to open a viewer on the source if index >= 0, then also sets the selection to the given index (for chars characters) Viewers/Section translations ... returns the selected viewer's name and the source index into the viewer. Returns [NIL, -1] if the selection is not in a valid Tioga viewer. ... returns a location for the given selection (primary or feedback); returns NIL if can't do it. If world = NIL then world _ LocalWorld. warn = TRUE => the version of the source file for the given location does not correspond to the viewer (although this is no guarantee that the wrong thing happened). This is a hack, by the way returns BcdDefs.NullVersion if any errors occur returns BcdDefs.NullVersion if any errors occur (like missing file) Rats! We have to try to get the create date from the remote host! returns NIL if the file is not available in the right source ... takes care of differences between CIFS and IFS file name formats. The file names are assumed in valid formats, although if they are not, the worst that can happen is a wrong answer. sigh, have to ignore this char, so backup the other position sigh, have to ignore this char, so backup the other position ... turns a long path name into a short path name, stripping off the version information and the directory, but preserving the extension. OnScreen determines whether or not the given location is visible for the given viewer. Now we know that we have a Tioga document At this point tdd is really and truly locked up. We must release it at the end of the block or bad things will happen. Code to export VersionMapOps a match, so add it to the list a match, so add it to the list test for the directory occuring in the right place file may be on local disk, so let's try it hooray, we can use the local file make a long name into a short one assumes a valid long name, of course [cmd: Handle] => [in, out, err: STREAM, commandLine,command: ROPE, propertyList: List.AList] [cmd: Handle] => [in, out, err: STREAM, commandLine,command: ROPE, propertyList: List.AList] [msg: ROPE, severity: Severity] => [in, out, err: STREAM, commandLine,command: ROPE, propertyList: List.AList] [cmd: Handle] => [in, out, err: STREAM, commandLine,command: ROPE, propertyList: List.AList] ÊD˜Jšœ™Jšœ&™&J˜šÏk ˜ Jšœ œ ˜šœ˜ Jšœ˜—Jšœœ?˜RJšœ œ)˜:Jšœœ$˜1J˜ Jšœ œ ˜Jšœœ˜*Jšœ œ!˜0Jšœœ˜Jšœ œ˜*Jšœœ˜Jšœ œ˜&Jšœœ˜Jšœ˜J˜Jšœœ˜&Jšœ ˜ Jšœœ ˜Jšœ˜Jšœœœ˜Jšœœ˜!Jšœœ ˜3Jšœ œ˜$Jšœœ ˜4Jšœ œ(˜:Jšœ œ˜(Jšœ œ˜Jšœ œ˜(šœ ˜JšœU˜U—Jšœ œ/˜?Jšœœ#˜;Jšœœ#˜6Jšœœ ˜Jšœ œ(˜7Jšœ œ6˜GJšœœ˜"J˜—J˜šÐblœœ˜Jšœrœœ±˜±Jšœ˜"Jšœ ˜Jšœœœ˜"J˜—šœ ™ J˜Jšœ œ˜ Jšœœ˜Jšœœ!˜6Jšœœ ˜4Jšœœ˜2Jšœœœ˜Jšœœœœ˜Jšœœ œ˜Jšœœ˜J˜—™J˜š œ œœœœœ˜:JšœL™L—Jšœ œœ˜Jšœœœ˜Jšœœœ˜Jšœœœ˜J˜Jšœœœ˜—J™šœ™J˜—Jš œ œœ œœ˜0Jš œ œœœœ˜AJ˜šÏn œœ˜Jš œœœœœ œ ˜LJšœœ™œJšœœœ˜šœœœ˜Jšœœ˜Jšœœ˜šœ(˜2šœ ˜ Jšœ9˜9—šœ˜Jšœ%˜%—šœ˜šœ/˜/Jšœ˜Jšœ$˜$—J˜—Jšœœ˜+—Jšœ(˜(Jšœ(˜(šœœœ˜Jšœ?˜?Jšœ˜—šœ œ˜šœ˜Jšœ"˜"Jšœœ˜——J˜—Jšœœœ˜J˜/J˜Jšœ œœ˜"šœ ˜Jšœ.˜2Jšœœ˜#—J˜J˜—šŸ œœ˜Jšœœ œ œ˜@Jšœ<™—Jšœ$˜$Jšœ˜Jšœ$˜$Jšœ"˜"J˜—Jšœ"˜&—Jšœ˜—šœ˜Jšœ˜—J˜J˜—šŸœœ˜Jšœœœ?œ˜XJšœ/™/Jšœœœœœœœ˜3J˜6J˜5J˜$J˜)š˜Jšœ œœ˜J˜ —J˜J˜—šŸ œœ˜Jšœœœ9œ˜VJšœC™CJšœœ,˜7šœ˜šœ˜Jšœœœ˜%Jšœœ˜Jšœ'œ˜7Jšœ œ˜Jšœœ-˜DJ˜—šœ˜Jšœœ œ˜$šœ ˜šœ˜JšœB™BJšœœ ˜Jšœœ˜Jšœœ˜&J˜J˜!šœ œœ˜'Jšœ!˜!J˜Jšœ#˜#J˜—JšœM˜MJšœ œœ ˜4J˜—š˜Jšœœ˜%——J˜——Jšœ ˜J˜J˜—šŸœœ˜Jšœ%œœœ˜EJšœ<™Jšœœ˜Jšœœ˜Jšœ,˜,Jšœ œœ˜šœœ˜ Jšœ*™*šœœ˜Jšœ!™!J˜ Jšœ œ˜—J˜—Jšœ"˜"J˜J˜—š Ÿ œœœœœ˜,Jšœ!™!Jšœ$™$Jšœœ˜Jšœœ ˜š œœ œœ ˜%Jšœœ˜šœ˜ Jšœœ˜J˜Jšœ˜ —Jšœ˜—Jšœ ˜&J˜J˜—šœ%œ˜.Jšœ ™ JšœN™NJšœœœ ˜Jšœœœ˜šœœœœ˜ Jš œ œœœœ˜ š˜Jšœœ˜Jšœœœ˜0Jšœœœ˜Jšœ/œœ˜<šœœœ˜Jšœ˜J˜J˜7Jšœ˜—šœ œœ˜Jšœ-˜-J˜J˜šœœ˜J˜J˜J˜J˜'J˜Jšœ˜—J˜Jšœ˜—Jšœ˜Jšœ˜—J˜—šœ˜ Jšœ%œ˜=Jšœ%œ˜@Jšœ˜—Jšœœœ˜5J˜J˜—šœ+œ˜4Jšœ ™ JšœN™NJšœœœ ˜Jšœœœ˜šœœœœ˜ Jš œ œœœœ˜ Jšœœœ˜ š˜Jšœ œœ˜Jšœœœ˜0Jšœœœ˜Jšœ*œœ˜Mšœœœ˜J˜J˜#Jšœ˜J˜—Jšœ,˜,šœ œ˜Jšœ&˜&—Jšœ˜—J˜—Jšœœœ˜5J˜J˜—šœ$œ˜-Jšœœ™JšœN™Nšœ:œ˜Išœ˜Jšœœœ ˜Jšœ˜J˜—Jšœ˜—J˜J˜—šŸœœœœ˜Tšœœœ˜J˜#J˜)J˜=J˜ šœœ˜J˜!šœ˜Jšœ˜Jšœ ˜—J˜ Jšœ˜—J˜—J˜J˜—šœ%œ˜.Jšœ ™ JšœN™NJšœœœ ˜šœœœœ˜ Jš œ œœœœ˜ š˜Jšœœ˜Jšœœœ˜0Jšœœœ˜Jšœ%œœ˜2šœœœ˜Jšœ˜J˜J˜7Jšœ˜—J˜J˜Jšœœœ˜ šœœœ˜Jšœ˜J˜J˜7Jšœ˜—šœœ˜J˜J˜J˜J˜'J˜J˜Jšœ˜—Jšœ˜—J˜—Jšœœœ˜5J˜J˜—šŸœœœ˜šœ˜J˜J˜Ž—šœ˜J˜J˜1—šœ˜J˜J˜(—šœ˜J˜J˜4—šœ˜J˜J˜‡—J˜J˜—Jšœ˜J˜J˜šœ˜J˜J˜——…—Ržz&