DIRECTORY Basics USING [Comparison], Buttons USING [Button, ButtonProc, Create], Containers USING [ChildXBound, ChildYBound, Container, Create], Labels USING [Create, Label, Set], Menus USING [CreateEntry, CreateMenu, InsertMenuEntry, Menu, MenuProc], Rules USING [Create, Rule], ViewerIO USING [CreateViewerStreams], ViewerOps USING [CreateViewer, PaintViewer, SetMenu, SetOpenHeight], ViewerClasses USING [Viewer], ViewerTools USING [MakeNewTextViewer, GetContents, SetContents, SetSelection], FS USING [StreamOpen ], GVNames USING [CheckStamp, Expand, ExpandInfo, GetFriends, GetMembers, MemberInfo, RListHandle, StampInfo], Histogram, IO USING [card, Close, Flush, PutF, PutFR, PutRope, rope, STREAM, time], RedBlackTree USING [Create, Delete, Insert, Key, Lookup, LookupNextLarger, LookupSmallest, Table, UserData], Rope USING [Cat, Compare, Equal, Fetch, Length, ROPE, SkipOver, SkipTo, Substr]; GVInvert: CEDAR MONITOR IMPORTS Buttons, Containers, Labels, Menus, Rules, ViewerIO, ViewerOps, ViewerTools, FS, GVNames, Histogram, IO, RedBlackTree, Rope = BEGIN ROPE: TYPE = Rope.ROPE; Invert: PROCEDURE = BEGIN ParseFileNamePattern: PROCEDURE = BEGIN f: ROPE = ViewerTools.GetContents[fileName]; starPosition: CARDINAL = Rope.SkipTo[f, 0, "*"]; IF starPosition = Rope.Length[f] OR Rope.SkipTo[f, starPosition+1, "*"] # Rope.Length[f] THEN BEGIN outStr.PutRope["\nFile name patterns should have exactly one *."]; ERROR inverterStopped END; fileNamePrefix _ Rope.Substr[f, 0, starPosition]; fileNameSuffix _ Rope.Substr[f, starPosition+1, Rope.Length[f] - starPosition+1]; END; --ParseFileNamePattern-- GetRegistryGroups: PROCEDURE [r: ROPE] = BEGIN c: CARDINAL; target: ROPE _ Rope.Cat["groups.", r]; rLH: GVNames.RListHandle; Labels.Set[currentName, target]; [rLH, c, ] _ MyExpand[target, FALSE]; registryList _ CONS[rLH, registryList]; totalGrp _ totalGrp + c; UpdateCounter[totalGroups, totalGrp]; END; --GetRegistryGroups-- CreateOutputFileForRegistry: PROCEDURE [reg: ROPE] = BEGIN data: RedBlackTree.UserData; acceptAll: BOOLEAN = Rope.Equal["other", reg, FALSE]; outStr.PutF["\nCreating output file for %g.", [rope[reg]]]; fH _ FS.StreamOpen[fileName: Rope.Cat[fileNamePrefix, reg, fileNameSuffix], accessOptions: create]; fH.PutF["DL inversion for the %g registry.\n\n%t\n\n\n\n", IO.rope[reg], IO.time[]]; data _ RedBlackTree.LookupSmallest[membersTable]; UNTIL data = NIL DO mR: REF MemberRecord _ NARROW[data]; key: ROPE _ mR.name; IF acceptAll OR Rope.Equal[reg, ExtractRegistry[key], FALSE] THEN {PrintMemberEntry[mR]; [] _ RedBlackTree.Delete[membersTable, key]}; data _ RedBlackTree.LookupNextLarger[membersTable, key]; ENDLOOP; fH.Flush[]; fH.Close[]; END; -- CreateOutputFileForRegistry-- PrintMemberEntry: PROCEDURE [mR: REF MemberRecord] = BEGIN groupPrinted: BOOLEAN _ FALSE; mbrStatus: MailStatus; numGroups: CARDINAL _ 0; PutGroup: PROC [group: ROPE, owners, friends: BOOLEAN] = BEGIN IF groupPrinted THEN fH.PutRope[", "] ELSE groupPrinted _ TRUE; IF owners THEN fH.PutRope["Owners("]; IF friends THEN fH.PutRope["Friends("]; fH.PutRope[group]; IF owners OR friends THEN fH.PutRope[")"]; END; --PutGroup-- Labels.Set[currentName, mR.name]; fH.PutF["\n\n%g", IO.rope[mR.name]]; mbrStatus _ PrintMailStatus[mR.name, mR.knownToBeIndividual]; fH.PutRope[" -- "]; IF mR.owner#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO IF mR.owner[j] THEN BEGIN PutGroup[groups[j], TRUE, FALSE]; IF mbrStatus=notRegistered THEN RecordBadMember[ tbl: badDLsTable, dl: Rope.Cat["Owners(", groups[j], ")"], mbr: mR.name]; END; ENDLOOP; IF mR.friend#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO IF mR.friend[j] THEN BEGIN PutGroup[groups[j], FALSE, TRUE]; IF mbrStatus=notRegistered THEN RecordBadMember[ tbl: badDLsTable, dl: Rope.Cat["Friends(", groups[j], ")"], mbr: mR.name]; END; ENDLOOP; IF mR.member#NIL THEN FOR j: CARDINAL IN [0 .. groups.length) DO IF mR.member[j] THEN BEGIN PutGroup[groups[j], FALSE, FALSE]; IF mbrStatus=notRegistered THEN RecordBadMember[tbl: badDLsTable, dl: groups[j], mbr: mR.name]; numGroups _ numGroups + 1; END; ENDLOOP; IF NOT groupPrinted THEN fH.PutRope["NONE"]; IF mbrStatus=inboxes THEN gram.DataPoint[MIN[numGroups, maxGram]]; currentMbrs _ currentMbrs + 1; UpdateCounter[currentMembers, currentMbrs]; END; --PrintMemberEntry-- Foreign: PROCEDURE [name: ROPE] RETURNS [BOOLEAN] = BEGIN reg: ROPE = ExtractRegistry[name]; IF foreignRegistries = NIL THEN BEGIN c: CARDINAL; fR: GVNames.RListHandle; AddThem: PROCEDURE[f: ROPE] RETURNS [done: BOOLEAN] = {foreignRegistries[c] _ Rope.Substr[f, 0, FindLastPeriod[f]]; c _ c+1; done _ FALSE}; Labels.Set[currentName, "individuals.foreign"]; [fR, c, ] _ MyExpand["individuals.foreign", TRUE]; foreignRegistries _ NEW [RopeSequence[c]]; c _ 0; EnumerateRList[fR, AddThem]; END; FOR i: CARDINAL IN [0 .. foreignRegistries.length) DO IF Rope.Equal[foreignRegistries[i], reg, FALSE] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; --Foreign-- MailStatus: TYPE = {notRegistered, invalid, forwarded, foreign, inboxes, group}; PrintMailStatus: PROCEDURE [name: ROPE, knownToBeIndividual: BOOLEAN] RETURNS [status: MailStatus]= BEGIN allDownDot: BOOLEAN _ FALSE; UNTIL Stopped[] DO nameType: GVNames.StampInfo _ IF knownToBeIndividual THEN individual ELSE GVNames.CheckStamp[name]; SELECT nameType FROM group => { fH.PutRope[" (group)"]; status _ group }; individual => BEGIN rLH: GVNames.RListHandle; c: CARDINAL; siteList: BOOLEAN; Labels.Set[currentName, name]; [rLH, c, siteList] _ MyExpand[name, TRUE]; IF c = 0 THEN { fH.PutRope[" (invalid recipient)"]; status _ invalid } ELSE BEGIN fH.PutRope[" ("]; IF NOT siteList THEN { fH.PutRope["->"]; status _ forwarded } ELSE status _ inboxes; fH.PutRope[NameListToRope[rLH]]; fH.PutRope[")"]; END; END; notFound => IF Foreign[name] THEN { fH.PutRope[" (foreign registry)"]; status _ foreign } ELSE BEGIN fH.PutRope[" (not registered)"]; status _ notRegistered; END; allDown => {ReportAllDown[allDownDot, name]; allDownDot_TRUE; LOOP}; ENDCASE => ERROR; EXIT; ENDLOOP; END; --PrintMailStatus-- InsertGrouplessIndividuals: PROCEDURE [reg: ROPE] = BEGIN RecordIfNonMember: PROCEDURE [n: ROPE] RETURNS [BOOLEAN] = BEGIN mR: REF MemberRecord _ NARROW[RedBlackTree.Lookup[membersTable, n]]; IF mR = NIL THEN mR _ MakeTableEntry[n, TRUE]; RETURN [FALSE]; END; --RecordIfNonMember-- g: ROPE = Rope.Cat["individuals.", reg]; Labels.Set[currentName, g]; EnumerateRList[MyExpand[g, TRUE].m, RecordIfNonMember]; END; --InsertGrouplessIndividuals-- ProcessGroup: PROCEDURE [group: ROPE] RETURNS [done: BOOLEAN] = BEGIN ownersList: ROPE = Rope.Cat["Owners-", group]; friendsList: ROPE = Rope.Cat["Friends-", group]; doingOwners, doingFriends: BOOLEAN _ FALSE; RecordMembership: PROCEDURE [n: ROPE] RETURNS [BOOLEAN] = BEGIN mR: REF MemberRecord _ NARROW[RedBlackTree.Lookup[membersTable, n]]; IF mR=NIL THEN mR _ MakeTableEntry[n, FALSE]; SELECT TRUE FROM doingOwners => BEGIN IF mR.owner=NIL THEN mR.owner _ NEW[Membership[groups.length]]; mR.owner[currentGrp] _ TRUE; END; doingFriends => BEGIN IF mR.friend=NIL THEN mR.friend _ NEW[Membership[groups.length]]; mR.friend[currentGrp] _ TRUE; END; ENDCASE => BEGIN IF mR.member=NIL THEN mR.member _ NEW[Membership[groups.length]]; mR.member[currentGrp] _ TRUE; END; RETURN [FALSE]; END; --RecordMembership-- Labels.Set[currentName, group]; UpdateCounter[currentGroups, currentGrp+1]; EnumerateRList[MyExpand[group, TRUE].m, RecordMembership]; doingFriends _ TRUE; EnumerateRList[MyGetFriends[group, TRUE].m, RecordMembership]; doingOwners _ TRUE; EnumerateRList[MyExpand[ownersList, TRUE].m, RecordMembership]; groups[currentGrp] _ group; currentGrp _ currentGrp+1; RETURN[FALSE] END; MakeTableEntry: PROCEDURE [n: ROPE, ind: BOOLEAN] RETURNS [mR: REF MemberRecord] = BEGIN mR _ NEW [MemberRecord]; mR.name _ n; mR.knownToBeIndividual _ ind; mR.owner _ NIL; mR.member _ NIL; totalMbrs _ totalMbrs + 1; UpdateCounter[totalMembers, totalMbrs]; RedBlackTree.Insert[membersTable, mR, n]; END; --MakeTableEntry-- UpdateCounter: PROCEDURE [l: Labels.Label, c: CARDINAL] = {Labels.Set[l, IO.PutFR[v1: IO.card[c]] ]}; registryList: LIST OF GVNames.RListHandle _ NIL; groups: REF RopeSequence; foreignRegistries: REF RopeSequence _ NIL; fH: IO.STREAM; membersTable: RedBlackTree.Table = RedBlackTree.Create[GetKey, MyCompare]; badDLsTable: RedBlackTree.Table = RedBlackTree.Create[GetKey, MyCompare]; currentGrp, totalGrp, currentMbrs, totalMbrs: CARDINAL _ 0; inputRegs: ROPE = ViewerTools.GetContents[registries]; fileNamePrefix: ROPE; fileNameSuffix: ROPE; maxGram: INT = 500; gram: Histogram.Gram = Histogram.NewGram[0, maxGram]; outStr.PutF["Running at %t.", IO.time[]]; Labels.Set[currentName, "none"]; UpdateCounter[totalGroups, 0]; UpdateCounter[currentGroups, 0]; UpdateCounter[totalMembers, 0]; UpdateCounter[currentMembers, 0]; ParseFileNamePattern[]; ForWordsInRopeDo[inputRegs, CheckRegistryValidity]; ForWordsInRopeDo[AllRegistries[], GetRegistryGroups]; groups _ NEW [RopeSequence[totalGrp]]; FOR registryList _ registryList, registryList.rest UNTIL registryList = NIL DO EnumerateRList[registryList.first, ProcessGroup]; ENDLOOP; ForWordsInRopeDo[inputRegs, InsertGrouplessIndividuals]; ForWordsInRopeDo[inputRegs, CreateOutputFileForRegistry]; PrintBadMembers[badDLsTable, inputRegs]; gram.Print[outStr, "\n\nNumber of DL's for each mail system user."]; outStr.PutF["\nDone at %t.\n\n", IO.time[]]; END;--Invert-- RopeSequence: TYPE = RECORD[SEQUENCE length: CARDINAL OF ROPE]; inverterStopped: ERROR = CODE; inversionInProgress: BOOLEAN _ FALSE; allRegistries: ROPE _ NIL; defaultRegistries: ROPE = "Arpa BITNET CHI Cholla COM CSNET DC DLOS EDU EOSA ES FX Guest Henr LB MAILNET NS OGC OSBUBayshore OSBUNorth OSBUSouth OSDA PA PASA RX SBDERX Siemens STHQ SV WBST X XRCC MS GV Other"; defaultFileNamePattern: ROPE = "///GV/*.txt"; stop: BOOLEAN _ FALSE; DoIt: Menus.MenuProc = BEGIN IF ReserveInverter[] THEN BEGIN Invert[ ! inverterStopped => {outStr.PutF["\nStopped at %t.\n\n", IO.time[]]; CONTINUE} ]; outStr.Flush[]; ReleaseInverter[]; END; END; -- DoIt-- StopIt: Menus.MenuProc = {SetStop[]}; ReserveInverter: ENTRY PROCEDURE RETURNS [BOOLEAN] = BEGIN IF inversionInProgress THEN RETURN [FALSE] ELSE {inversionInProgress _ TRUE; RETURN[TRUE]}; END; ReleaseInverter: ENTRY PROCEDURE = {inversionInProgress _ FALSE; stop _ FALSE}; SetStop: ENTRY PROCEDURE = {stop _ TRUE}; StopSet: ENTRY PROCEDURE RETURNS [BOOLEAN] = INLINE {RETURN [stop]}; Stopped: PROCEDURE RETURNS [BOOLEAN] = {IF StopSet[] THEN ERROR inverterStopped ELSE RETURN[FALSE]}; AllRegistries: PROCEDURE RETURNS[ROPE] = BEGIN ExtractRegistry: PROCEDURE [r: ROPE] RETURNS [done: BOOLEAN] = BEGIN allRegistries _ Rope.Cat[allRegistries, " ", Rope.Substr[r, 0, FindLastPeriod[r]]]; done _ FALSE; END; IF allRegistries = NIL THEN { Labels.Set[currentName, "groups.gv"]; EnumerateRList[ MyExpand["groups.gv", FALSE].m, ExtractRegistry]; }; RETURN [ allRegistries ]; END; --AllRegistries-- FindLastPeriod: PROCEDURE[r: ROPE] RETURNS [lastPeriod: CARDINAL] = BEGIN FOR i: INT DECREASING IN [0 .. Rope.Length[r]) DO IF Rope.Fetch[r, i] = '. THEN {lastPeriod _ i; EXIT}; REPEAT FINISHED => lastPeriod _ Rope.Length[r]; ENDLOOP; END; --FindLastPeriod-- ReportAllDown: PROCEDURE [dot: BOOLEAN, name: ROPE] = BEGIN IF dot THEN outStr.PutRope["."] ELSE outStr.PutF["\nAll down: %g. ", [rope[name]]]; END; MyExpand: PROCEDURE [eName: ROPE, ignoreNotFound: BOOLEAN] RETURNS [m: GVNames.RListHandle, c: CARDINAL, isSiteList: BOOLEAN] = BEGIN printDot: BOOLEAN _ FALSE; ReportNotFound: PROCEDURE = {outStr.PutF["%g%g\n\n", [rope[eName]], [rope[" not found."]]]; ERROR inverterStopped}; UNTIL Stopped[] DO WITH GVNames.Expand[eName] SELECT FROM g: GVNames.ExpandInfo[group] => {m _ g.members; c _ g.count; isSiteList _ FALSE}; i: GVNames.ExpandInfo[individual] => {m _ i.sites; c _ i.count; isSiteList _ TRUE}; n: GVNames.ExpandInfo[notFound] => WITH GVNames.GetMembers[eName] SELECT FROM g: GVNames.MemberInfo[group] => {m _ g.members; c _ g.count; isSiteList _ FALSE}; n: GVNames.MemberInfo[notFound] => IF ignoreNotFound THEN {m _ NIL; c _ 0} ELSE ReportNotFound[]; a: GVNames.MemberInfo[allDown] => {ReportAllDown[printDot, eName]; printDot _ TRUE; LOOP}; ENDCASE => ERROR; a: GVNames.ExpandInfo[allDown] => {ReportAllDown[printDot, eName]; printDot _ TRUE; LOOP}; ENDCASE => ERROR; EXIT; ENDLOOP; END; --MyExpand-- MyGetFriends: PROCEDURE [eName: ROPE, ignoreNotFound: BOOLEAN] RETURNS [m: GVNames.RListHandle, c: CARDINAL, isSiteList: BOOLEAN] = BEGIN printDot: BOOLEAN _ FALSE; ReportNotFound: PROCEDURE = {outStr.PutF["%g%g\n\n", [rope[eName]], [rope[" not found."]]]; ERROR inverterStopped}; UNTIL Stopped[] DO WITH GVNames.GetFriends[eName] SELECT FROM g: GVNames.MemberInfo[group] => {m _ g.members; c _ g.count; isSiteList _ FALSE}; i: GVNames.MemberInfo[individual] => ERROR; n: GVNames.MemberInfo[notFound] => IF ignoreNotFound THEN {m _ NIL; c _ 0; isSiteList _ FALSE} ELSE ReportNotFound[]; a: GVNames.MemberInfo[allDown] => {ReportAllDown[printDot, eName]; printDot _ TRUE; LOOP}; ENDCASE => ERROR; EXIT; ENDLOOP; END; ExtractRegistry: PROCEDURE [RName: ROPE] RETURNS [registry: ROPE] = BEGIN start: CARDINAL _ FindLastPeriod[RName]+1; RETURN [IF start >= Rope.Length[RName] THEN NIL ELSE Rope.Substr[RName, start, Rope.Length[RName] - start]] END; --ExtractRegistry-- NameListToRope: PROCEDURE [mLH: GVNames.RListHandle] RETURNS [r: ROPE] = BEGIN AddMemberToRope: PROCEDURE[m: ROPE] RETURNS [done: BOOLEAN] = BEGIN IF r # NIL THEN r _ Rope.Cat[r, ", "]; r _ Rope.Cat[r, m]; done _ FALSE END; r _ NIL; EnumerateRList[mLH, AddMemberToRope]; END; --NameListToRope-- ForWordsInRopeDo: PROCEDURE [r: ROPE, work: PROCEDURE[ROPE]] = BEGIN parsePosition: CARDINAL _ Rope.SkipOver[r, 0, " "]; -- skip initial blanks UNTIL parsePosition = Rope.Length[r] DO --parse registry input-- start: CARDINAL = parsePosition; parsePosition _ Rope.SkipTo[r, parsePosition, " "]; work[Rope.Substr[r, start, parsePosition-start]]; parsePosition _ Rope.SkipOver[r, parsePosition, " "]; ENDLOOP; END; -- ForWordsInRopeDo -- EnumerateRList: PROCEDURE [r: GVNames.RListHandle, p: PROCEDURE [ROPE] RETURNS [BOOLEAN] ] = {FOR r _ r, r.rest UNTIL r=NIL OR p[r.first] DO ENDLOOP}; ValidNameWithStar: PROCEDURE [reg: ROPE] RETURNS [ok: BOOL] = BEGIN printDot: BOOLEAN _ FALSE; length: INT _ Rope.Length[reg]; IF Rope.Equal[reg, "*"] THEN RETURN [TRUE]; IF length < 3 THEN RETURN [FALSE]; IF Rope.Fetch[reg, 0] # '* THEN RETURN [FALSE]; IF Rope.Fetch[reg, 1] # '. THEN RETURN [FALSE]; reg _ Rope.Substr[reg, 2, length-2]; UNTIL Stopped[] DO name: ROPE _ Rope.Cat[reg, ".gv"]; SELECT GVNames.CheckStamp[name] FROM group => RETURN [TRUE]; individual => RETURN [FALSE]; notFound => RETURN [FALSE]; allDown => {ReportAllDown[printDot, name]; printDot_TRUE; LOOP}; ENDCASE => ERROR; ENDLOOP; END; CheckRegistryValidity: PROCEDURE [reg: ROPE] = BEGIN printDot: BOOLEAN _ FALSE; ReportInvalidRegistry: PROCEDURE = BEGIN outStr.PutF["%g%g\n\n", [rope[reg]], [rope[" is not a valid registry."]]]; ERROR inverterStopped; END; IF Rope.Equal["other", reg, FALSE] THEN RETURN; UNTIL Stopped[] DO name: ROPE _ Rope.Cat[reg, ".gv"]; SELECT GVNames.CheckStamp[name] FROM group => NULL; individual => ReportInvalidRegistry[]; notFound => BEGIN name _ Rope.Cat[reg, ".foreign"]; SELECT GVNames.CheckStamp[name] FROM group, notFound => ReportInvalidRegistry[]; individual => NULL; allDown => {ReportAllDown[printDot, name]; printDot_TRUE; LOOP}; ENDCASE => ERROR; END; allDown => {ReportAllDown[printDot, name]; printDot_TRUE; LOOP}; ENDCASE => ERROR; EXIT; ENDLOOP; END; --CheckRegistryValidity-- BadDL: TYPE = RECORD [name: ROPE, badMbr: LIST OF ROPE]; RecordBadMember: PROC [tbl: RedBlackTree.Table, dl, mbr: ROPE] = BEGIN dlEntry: REF BadDL; IF ValidNameWithStar[mbr] THEN RETURN; dlEntry _ NARROW[RedBlackTree.Lookup[tbl, dl]]; IF dlEntry = NIL THEN { dlEntry _ NEW[BadDL]; dlEntry.name _ dl; dlEntry.badMbr _ NIL; RedBlackTree.Insert[tbl, dlEntry, dl]; }; dlEntry.badMbr _ CONS[mbr, dlEntry.badMbr]; END; --RecordBadMember-- PrintBadMembers: PROC [tbl: RedBlackTree.Table, inputRegistries: ROPE] = BEGIN PrintBadDLsForRegistry: PROCEDURE [reg: ROPE] = BEGIN needRegistryLabel: BOOLEAN _ TRUE; acceptAll: BOOLEAN = Rope.Equal["other", reg, FALSE]; data: RedBlackTree.UserData; data _ RedBlackTree.LookupSmallest[tbl]; UNTIL data = NIL DO dl: REF BadDL _ NARROW[data]; key: ROPE _ dl.name; IF Rope.Equal[reg, ExtractRegistry[key], FALSE] OR acceptAll THEN BEGIN firstName: BOOLEAN _ TRUE; IF needRegistryLabel THEN BEGIN IF needTitle THEN BEGIN outStr.PutRope["\n\n\nDL's with members that are NOT REGISTERED."]; needTitle _ FALSE; END; outStr.PutF["\n\n\n""%g"" registry:\n", IO.rope[reg]]; needRegistryLabel _ FALSE; END; Labels.Set[currentName, dl.name]; outStr.PutF["\n\n%g -- ", IO.rope[key]]; FOR mbr: LIST OF ROPE _ dl.badMbr, mbr.rest UNTIL mbr=NIL DO IF firstName THEN firstName _ FALSE ELSE outStr.PutRope[", "]; outStr.PutRope[mbr.first]; ENDLOOP; [] _ RedBlackTree.Delete[tbl, key]; END; data _ RedBlackTree.LookupNextLarger[tbl, key];ENDLOOP; END; --PrintBadDLsForRegistry-- needTitle: BOOLEAN _ TRUE; ForWordsInRopeDo[inputRegistries, PrintBadDLsForRegistry]; IF needTitle THEN outStr.PutRope["No bad members.\n"] END; --PrintBadMembers-- Membership: TYPE = RECORD[PACKED SEQUENCE length: CARDINAL OF BOOLEAN]; MemberRecord: TYPE = RECORD[name: ROPE, knownToBeIndividual: BOOLEAN, owner, friend, member: REF Membership]; GetKey: SAFE PROC [data: RedBlackTree.UserData] RETURNS [key: RedBlackTree.Key] = { WITH data SELECT FROM m: REF MemberRecord => key _ m.name; d: REF BadDL => key _ d.name; r: ROPE => key _ r; ENDCASE => ERROR; }; MyCompare: SAFE PROC [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison] = CHECKED BEGIN a: ROPE _ NARROW[k]; b: ROPE _ NARROW[GetKey[data]]; RETURN [Rope.Compare[a, b, FALSE]] END; --compareMbrs-- entryHeight: CARDINAL = 15; entryVSpace: CARDINAL = 10; entryHSpace: CARDINAL = 10; heightSoFar: CARDINAL _ 0; container: Containers.Container; currentMembers, totalMembers: Labels.Label; currentGroups, totalGroups: Labels.Label; currentName: Labels.Label; exceptions: ViewerClasses.Viewer; inStr, outStr: IO.STREAM; fileName, registries: ViewerClasses.Viewer; BuildOuter: PROC = BEGIN myMenu: Menus.Menu _ Menus.CreateMenu[]; container _ Containers.Create[info: [name: "InvertDLs", scrollable: FALSE] ]; Menus.InsertMenuEntry[menu: myMenu, entry: Menus.CreateEntry[name: "DoIt", proc: DoIt] ]; Menus.InsertMenuEntry[menu: myMenu, entry: Menus.CreateEntry[name: "Stop", proc: StopIt] ]; ViewerOps.SetMenu[viewer: container, menu: myMenu]; BuildUserInput[]; BuildUserFeedback[]; BuildExceptions[]; ViewerOps.SetOpenHeight[viewer: container, clientHeight: heightSoFar]; ViewerOps.PaintViewer[viewer: container, hint: all]; END; BuildUserInput: PROC = BEGIN l1, l2: Buttons.Button; heightSoFar _ heightSoFar+entryVSpace/2; l1 _ Buttons.Create[info: [name: "File name pattern (* for registry):", parent: container, border: FALSE, wy: heightSoFar], proc: ForceSelToFileName]; fileName _ ViewerTools.MakeNewTextViewer[info: [parent: container, wx: l1.wx+l1.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: entryHeight, data: defaultFileNamePattern, scrollable: FALSE, border: FALSE], paint: FALSE]; Containers.ChildXBound[container, fileName]; heightSoFar _ heightSoFar+entryVSpace+l1.wh; l2 _ Buttons.Create[info: [name: "Registries:", parent: container, border: FALSE, wy: heightSoFar], proc: ForceSelToRegistries]; registries _ ViewerTools.MakeNewTextViewer[info: [parent: container, wx: l2.wx+l2.ww+entryHSpace, wy: heightSoFar, ww: 0, wh: 3*entryHeight, data: defaultRegistries, scrollable: TRUE, border: FALSE], paint: FALSE]; Containers.ChildXBound[container, registries]; heightSoFar _ heightSoFar+entryVSpace+registries.wh; END; ForceSelToFileName: Buttons.ButtonProc = BEGIN IF mouseButton#red THEN ViewerTools.SetContents[fileName, defaultFileNamePattern] ELSE ViewerTools.SetSelection[fileName]; END; ForceSelToRegistries: Buttons.ButtonProc = BEGIN IF mouseButton#red THEN ViewerTools.SetContents[registries, defaultRegistries] ELSE ViewerTools.SetSelection[registries]; END; BuildUserFeedback: PROC = BEGIN li, lg, ln, of: Labels.Label; r1: Rules.Rule; r1 _ Rules.Create[info: [parent: container, wx: 0, wy: heightSoFar, ww: 0, wh:1]]; Containers.ChildXBound[container, r1]; heightSoFar _ heightSoFar+entryVSpace; li _ Labels.Create[info: [name: "Members:", parent: container, wx: 0, wy: heightSoFar, border: FALSE]]; currentMembers _ Labels.Create[info: [name: "0000", parent: container, wx: li.wx+li.ww+entryHSpace, wy: heightSoFar, border: TRUE]]; Labels.Set[currentMembers, "0"]; of _ Labels.Create[info: [name: "of", parent: container, wx: currentMembers.wx+currentMembers.ww+entryHSpace, wy: heightSoFar, border: FALSE]]; totalMembers _ Labels.Create[info: [name: "0000", parent: container, wx: of.wx+of.ww+entryHSpace, wy: heightSoFar, border: TRUE]]; Labels.Set[totalMembers, "0"]; lg _ Labels.Create[info: [name: "Groups:", parent: container, wx: totalMembers.wx+totalMembers.ww+entryHSpace+entryHSpace, wy: heightSoFar, border: FALSE]]; currentGroups _ Labels.Create[info: [name: "0000", parent: container, wx: lg.wx+lg.ww+entryHSpace, wy: heightSoFar, border: TRUE]]; Labels.Set[currentGroups, "0"]; of _ Labels.Create[info: [name: "of", parent: container, wx: currentGroups.wx+currentGroups.ww+entryHSpace, wy: heightSoFar, border: FALSE]]; totalGroups _ Labels.Create[info: [name: "0000", parent: container, wx: of.wx+of.ww+entryHSpace, wy: heightSoFar, border: TRUE]]; Labels.Set[totalGroups, "0"]; heightSoFar _ heightSoFar+entryVSpace+of.wh; ln _ Labels.Create[info: [name: "Current Name:", parent: container, wx: 0, wy: heightSoFar, border: FALSE]]; currentName _ Labels.Create[info: [name: "", parent: container, wx: ln.wx+ln.ww+entryHSpace, wy: heightSoFar, border: FALSE]]; Labels.Set[currentName, "none"]; Containers.ChildXBound[container, currentName]; heightSoFar _ heightSoFar+entryVSpace+of.wh; END; BuildExceptions: PROC = BEGIN r2: Rules.Rule; r2 _ Rules.Create[info: [parent: container, wx: 0, wy: heightSoFar, ww: 0, wh: 1]]; Containers.ChildXBound[container, r2]; heightSoFar _ heightSoFar+entryVSpace; exceptions _ ViewerOps.CreateViewer[flavor: $Typescript, info: [name: "", parent: container, wx: 0, wy: heightSoFar, wh: 5*entryHeight, border: FALSE]]; heightSoFar _ heightSoFar+exceptions.wh; Containers.ChildXBound[container, exceptions]; Containers.ChildYBound[container, exceptions]; [in: inStr, out: outStr] _ ViewerIO.CreateViewerStreams[name: "", viewer: exceptions, backingFile: "InvertDLs.log"]; END; BuildOuter[]; END.. zGVInvert.mesa; HGM, November 20, 1984 9:46:45 pm PST Copyright c 1985 by Xerox Corporation. All rights reserved. Edited by Schroeder on March 19, 1983 2:35 pm Hal Murray May 7, 1985 11:58:32 pm PDT Ron Weaver August 30, 1985 11:15:05 am PDT Can't get here **************** Viewers set up stuff **************** ******************** Initialization ********************-- Κθ˜šΟc4™4Icodešœ Οmœ1™<—šœ-™-K™&K™*—J˜JšΟk ˜ ˜JšœŸœ˜JšœŸœ˜+Jšœ Ÿœ/˜?JšœŸœ˜#JšœŸœ=˜HJšœŸœ˜Jšœ Ÿœ˜%Jšœ Ÿœ6˜EJšœŸœ ˜Jšœ Ÿœ=˜NJ˜JšŸœŸœ˜šœŸœE˜RJ˜—J˜ JšŸœŸœ2Ÿœ˜Hšœ Ÿœ˜+Jšœ@˜@—JšœŸœ&Ÿœ˜PJ˜—šœ ŸœŸœŸ˜J˜LJšŸœŸœ˜0—JšŸ˜J˜JšŸœŸœŸœ˜J˜šΟnœŸ œ˜JšŸ˜J˜š œŸ œ˜!JšŸ˜JšœŸœ%˜,JšœŸœ˜0šŸœ˜ JšŸœ6ŸœŸ˜BJ˜BJšŸœ˜JšŸœ˜—J˜1J˜QJšŸœ˜J˜—š œŸ œŸœ˜(JšŸ˜JšœŸœ˜ JšœŸœ˜&J˜Jšœ ˜ JšœŸœ˜%JšœŸœ˜'J˜J˜%JšŸœ˜J˜—š œŸ œŸœ˜4JšŸ˜Jšœ˜Jšœ ŸœŸœ˜5J˜;šœŸœD˜KJ˜—Jšœ;Ÿœ Ÿœ ˜TJšœ1˜1šŸœŸœŸ˜JšœŸœŸœ˜$JšœŸœ ˜šŸœ Ÿœ'ŸœŸ˜AJšœD˜D—Jšœ8˜8JšŸœ˜—J˜ J˜ JšŸœ ˜%J˜—š œŸ œŸœ˜4JšŸ˜JšœŸœŸœ˜J˜Jšœ Ÿœ˜š œŸœ ŸœŸœ˜8JšŸ˜JšŸœŸœŸœŸœ˜?JšŸœŸœ˜%JšŸœ Ÿœ˜'J˜JšŸœŸœ Ÿœ˜*JšŸœ ˜—J˜!JšœŸœ˜$J˜=J˜š Ÿœ ŸœŸœŸœŸœŸœŸ˜?šŸœ ŸœŸ˜JšœŸœŸœ˜!šŸœŸ˜˜J˜I——JšŸœ˜—JšŸœ˜—š Ÿœ ŸœŸœŸœŸœŸœŸ˜@šŸœŸœŸ˜JšœŸœŸœ˜!šŸœŸ˜˜J˜J——JšŸœ˜—JšŸœ˜—š Ÿœ ŸœŸœŸœŸœŸœŸ˜@šŸœŸœŸ˜JšœŸœŸœ˜"šŸœŸ˜J˜?—J˜JšŸœ˜—JšŸœ˜—JšŸœŸœŸœ˜,KšŸœŸœŸœ˜BJ˜J˜+JšŸœ˜J˜š  œŸ œŸœŸœŸœ˜3JšŸ˜JšœŸœ˜"šŸœŸœŸœŸ˜%JšœŸœ˜ J˜š  œŸ œŸœŸœŸœ˜5JšœOŸœ˜V—Jšœ/˜/Jšœ,Ÿœ˜2JšœŸœ˜*J˜J˜JšŸœ˜—šŸœŸœŸœ!Ÿ˜5Jš Ÿœ'ŸœŸœŸœŸœ˜BJšŸœ˜—JšŸœŸœ˜JšŸœ ˜J˜—Jšœ ŸœA˜QJ˜š œŸ œŸœŸœ˜EJšŸœ˜JšŸ˜Jšœ ŸœŸœ˜šŸœ Ÿ˜šœŸœ˜4JšŸœ Ÿœ˜.—šŸœ Ÿ˜˜J˜+—šœŸ˜J˜JšœŸœ˜ Jšœ Ÿœ˜Jšœ˜Jšœ$Ÿœ˜*šŸœ˜JšŸœ9˜=šŸœŸ˜ J˜šŸœŸœ ˜JšŸœ)˜-JšŸœ˜—J˜ J˜JšŸœ˜——JšŸœ˜—˜ šŸœ˜JšŸœ8˜<šŸœŸ˜ J˜ J˜JšŸœ˜———˜ Jšœ-ŸœŸœ˜9—JšŸœŸœ˜—JšŸœ˜JšŸœ˜—JšŸœ˜J˜—š œŸ œŸœ˜3JšŸ˜š  œŸ œŸœŸœŸœ˜:JšŸ˜JšœŸœŸœ'˜DJšŸœŸœŸœŸœ˜.JšŸœŸœ˜JšŸœ˜—JšœŸœ!˜(J˜JšœŸœ˜8JšŸœ˜#J˜—š   œŸ œ ŸœŸœŸœ˜?JšŸ˜Jšœ Ÿœ˜.Jšœ Ÿœ˜0JšœŸœŸœ˜+š  œŸ œŸœŸœŸœ˜9JšŸ˜JšœŸœŸœ'˜DJšŸœŸœŸœŸœ˜-šŸœŸœŸ˜˜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˜J˜—š œŸ œŸœŸœ˜1JšŸœŸœ˜ JšŸ˜JšœŸœ˜J˜ J˜Jšœ Ÿœ˜Jšœ Ÿœ˜J˜J˜'Jšœ)˜)JšŸœ˜J˜—š  œŸ œŸœ˜9JšœŸœ Ÿœ ˜+J˜—JšœŸœŸœŸœ˜0JšœŸœ˜JšœŸœŸœ˜*JšœŸœŸœ˜JšœJ˜JJšœI˜IJšœ.Ÿœ˜;Jšœ Ÿœ'˜6JšœŸœ˜JšœŸœ˜Jšœ Ÿœ˜Jšœ5˜5J˜JšœŸœ ˜)J˜ J˜J˜ J˜J˜!J˜J˜3J˜5Jšœ Ÿœ˜&šŸœ0ŸœŸœŸ˜NJ˜1JšŸœ˜—J˜8J˜9J˜(J˜DJšœ!Ÿœ ˜,J˜JšŸœ ˜J˜——Jš œŸœŸœŸœ ŸœŸœŸœ˜?J˜JšœŸœŸœ˜JšœŸœŸœ˜&JšœŸœŸœ˜JšœŸœΊ˜ΡJšœŸœ˜.JšœŸœŸœ˜J˜˜JšŸ˜šŸœŸ˜JšŸ˜JšœBŸœ Ÿœ˜ZJ˜J˜JšŸœ˜—JšŸœ ˜J˜—˜J˜ J˜—š  œŸœŸ œŸœŸœ˜4JšŸ˜šŸœ˜JšŸœŸœŸœ˜JšŸœŸœŸœŸœ˜0—JšŸœ˜J˜—š œŸœŸ œ˜#JšœŸœ Ÿœ˜,J˜—š œŸœŸ œ˜JšœŸœ˜J˜—š  œŸœŸ œŸœŸœŸ˜3JšœŸœ ˜J˜—š œŸ œŸœŸœ˜&Jš œŸœ ŸœŸœŸœŸœŸœ˜=J˜—š  œŸ œŸœŸœ˜(JšŸ˜š  œŸ œŸœŸœŸœ˜>JšŸ˜J˜SJšœŸœ˜ JšŸœ˜—šŸœŸœŸ˜Jšœ%˜%Jšœ&Ÿœ˜D—JšŸœ˜JšŸœ˜J˜J˜—š  œŸ œŸœŸœŸœ˜CJšŸ˜š ŸœŸœŸ œŸœŸ˜1JšŸœŸœŸœ˜5JšŸœŸœ ˜/JšŸœ˜ —JšŸœ˜J˜—š  œŸ œŸœŸœ˜5JšŸ˜šŸœ˜JšŸœ˜JšŸœ/˜3—JšŸœ˜J˜—š œŸ œ ŸœŸœ˜:JšŸœŸœŸœ˜DJšŸ˜Jšœ ŸœŸœ˜š œŸ œ˜Jšœ@Ÿœ˜W—šŸœ Ÿ˜šŸœŸœŸ˜&˜Jšœ*Ÿœ˜1—˜$Jšœ(Ÿœ˜.—˜"šŸœŸœŸ˜*˜Jšœ*Ÿœ˜1—˜"šŸœ˜JšŸœŸœ˜JšŸœ˜——˜!Jšœ,ŸœŸœ˜8—JšŸœŸœ˜——˜!Jšœ,ŸœŸœ˜8—JšŸœŸœ˜—JšŸœ˜JšŸœ˜—JšŸœ ˜J˜—š  œŸ œ ŸœŸœ˜>JšŸœŸœŸœ˜DJšŸ˜Jšœ ŸœŸœ˜š œŸ œ˜Jšœ@Ÿœ˜W—šŸœ Ÿ˜šŸœŸœŸ˜*˜Jšœ*Ÿœ˜1—Jšœ%Ÿœ˜+˜"šŸœ˜JšŸœŸœŸœ˜)JšŸœ˜——˜!Jšœ,ŸœŸœ˜8—JšŸœŸœ˜—JšŸœ˜JšŸœ˜—JšŸœ˜J˜—š  œŸ œ ŸœŸœ Ÿœ˜CJšŸ˜JšœŸœ˜*šŸœŸœ˜&JšŸœŸœŸœ7˜D—JšŸœ˜J˜—š œŸ œŸœŸœ˜HJšŸ˜š  œŸ œŸœŸœŸœ˜=JšŸ˜JšŸœŸœŸœ˜&J˜JšœŸ˜ JšŸœ˜—JšœŸœ˜J˜%JšŸœ˜J˜—š  œŸ œŸœŸ œŸœ˜>JšŸ˜JšœŸœ˜JšŸœ Ÿœ˜@JšœŸœ˜ J˜3J˜1J˜5JšŸœ˜—JšŸœ˜J˜—š œŸ œ˜2Jš œŸ œŸœŸœŸœ˜)Jš œŸœŸœŸœŸœ ŸœŸœ˜9J˜—š  œŸ œŸœŸœŸœ˜=JšŸ˜Jšœ ŸœŸœ˜J˜JšŸœŸœŸœŸœ˜+JšŸœ ŸœŸœŸœ˜"JšŸœŸœŸœŸœ˜/JšŸœŸœŸœŸœ˜/Jšœ$˜$šŸœ Ÿ˜JšœŸœ˜"šŸœŸ˜$JšœŸœŸœ˜JšœŸœŸœ˜Jšœ ŸœŸœ˜˜ Jšœ)ŸœŸœ˜5—JšŸœŸœ˜—Jšœ™JšŸœ˜—JšŸœ˜J˜—š œŸ œŸœ˜.JšŸ˜Jšœ ŸœŸœ˜š œŸ œ˜"JšŸ˜J˜JJšŸœ˜JšŸœ˜—JšŸœŸœŸœŸœ˜/šŸœ Ÿ˜JšœŸœ˜"šŸœŸ˜$˜JšŸœ˜—˜ J˜—˜ JšŸ˜J˜!šŸœŸ˜$˜J˜—˜ JšŸœ˜—˜ Jšœ)ŸœŸœ˜5—JšŸœŸœ˜—JšŸœ˜—˜ Jšœ)ŸœŸœ˜5—JšŸœŸœ˜—JšŸœ˜JšŸœ˜—JšŸœ˜J˜J˜—Jš œŸœŸœŸœ ŸœŸœŸœ˜8J˜š œŸœ$Ÿœ˜@JšŸ˜Jšœ Ÿœ˜JšŸœŸœŸœ˜&Jšœ Ÿœ˜/šŸœ ŸœŸœŸ˜Jšœ Ÿœ˜J˜JšœŸœ˜Jšœ&Ÿœ˜)—JšœŸœ˜+JšŸœ˜J˜—š œŸœ,Ÿœ˜HJšŸ˜š œŸ œŸœ˜/JšŸ˜JšœŸœŸœ˜"Jšœ ŸœŸœ˜5Jšœ˜Jšœ(˜(šŸœŸœŸ˜JšœŸœ Ÿœ˜JšœŸœ ˜šŸœ'ŸœŸœ Ÿ˜AJšŸ˜Jšœ ŸœŸœ˜šŸœŸœŸ˜šŸœ ŸœŸ˜J˜CJšœ Ÿœ˜JšŸœ˜—Jšœ(Ÿœ ˜6JšœŸœ˜JšŸœ˜—J˜!JšœŸœ ˜(š ŸœŸœŸœŸœŸœŸœŸ˜J˜JšŸœ˜—Jšœ#˜#JšŸœ˜—Jšœ/Ÿœ˜7—JšŸœ˜—Jšœ ŸœŸœ˜J˜:JšŸœ Ÿœ$˜5JšŸœ˜J˜J˜—Jšœ ŸœŸœŸœŸœ ŸœŸœŸœ˜GJ˜š œŸœŸœŸœŸœ˜EJšœŸœ ˜'J˜—š œŸœŸœŸœ˜SšŸœŸœŸ˜JšœŸœ˜$JšœŸœ˜JšœŸœ ˜JšŸœŸœ˜——J˜š  œŸœŸœ3Ÿœ˜eJšŸœŸ˜ JšœŸœŸœ˜JšœŸœŸœ˜JšŸœŸœ˜"JšŸœ˜J˜J˜—Jšœ6™6J˜Jšœ Ÿœ˜Jšœ Ÿœ˜Jšœ Ÿœ˜J˜Jšœ Ÿœ˜J˜J˜!J˜+J˜)J˜J˜!JšœŸœŸœ˜J˜J˜+J˜š  œŸœ˜JšŸ˜J˜(JšœDŸœ˜M˜#J˜2J˜—˜#J˜4J˜—J˜3J˜J˜J˜J˜FJ˜4JšŸœ˜J˜—š œŸœ˜JšŸ˜J˜J˜(˜GJšœŸœ.˜N—˜BJ˜EJšœ*Ÿœ Ÿœ Ÿœ˜O—J˜,J˜,˜BJšœŸœ0˜=—˜DJ˜GJšœ%Ÿœ Ÿœ Ÿœ˜I—J˜.J˜4JšŸœ˜J˜—˜(JšŸ˜šŸœ˜JšŸœ:˜>JšŸœ$˜(—JšŸœ˜J˜—˜*JšŸ˜šŸœ˜JšŸœ7˜;JšŸœ&˜*—JšŸœ˜J˜—š œŸœ˜JšŸ˜J˜J˜J˜RJ˜&J˜&˜VJšœŸœ˜—˜FJšœ6Ÿœ˜=—J˜ ˜8JšœNŸœ˜V—˜DJšœ6Ÿœ˜=—J˜˜=J˜MJšœŸœ˜—˜EJšœ6Ÿœ˜=—J˜˜8JšœLŸœ˜T—˜`JšœŸœ˜ —J˜J˜,˜[JšœŸœ˜—˜\JšœŸœ˜!—J˜ J˜/J˜,JšŸœ˜J˜—š œŸœ˜JšŸ˜J˜J˜SJ˜&J˜&˜8J˜NJšœŸœ˜—J˜(J˜.J˜.˜UJ˜—JšŸœ˜J˜J˜—Jšœ:™:J˜J˜J˜ J˜JšŸœ˜J˜J˜J˜—…—XΤu6